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 List<IExpressionCleanup> epilogue_expressions;
88 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type, SourceMethodBuilder methodSymbols)
90 this.member_context = rc;
92 this.return_type = return_type;
94 if (rc.Module.Compiler.Settings.Checked)
95 flags |= Options.CheckedScope;
97 if (methodSymbols != null) {
98 this.methodSymbols = methodSymbols;
99 if (!rc.Module.Compiler.Settings.Optimize)
100 flags |= Options.AccurateDebugInfo;
102 flags |= Options.OmitDebugInfo;
106 ig.__CleverExceptionBlockAssistance ();
112 internal AsyncTaskStorey AsyncTaskStorey {
114 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
118 public BuiltinTypes BuiltinTypes {
120 return MemberContext.Module.Compiler.BuiltinTypes;
124 public TypeSpec CurrentType {
125 get { return member_context.CurrentType; }
128 public TypeParameters CurrentTypeParameters {
129 get { return member_context.CurrentTypeParameters; }
132 public MemberCore CurrentTypeDefinition {
133 get { return member_context.CurrentMemberDefinition; }
136 public bool EmitAccurateDebugInfo {
138 return (flags & Options.AccurateDebugInfo) != 0;
142 public bool HasMethodSymbolBuilder {
144 return methodSymbols != null;
148 public bool HasReturnLabel {
150 return return_label.HasValue;
154 public bool IsStatic {
155 get { return member_context.IsStatic; }
158 public bool IsAnonymousStoreyMutateRequired {
160 return CurrentAnonymousMethod != null &&
161 CurrentAnonymousMethod.Storey != null &&
162 CurrentAnonymousMethod.Storey.Mutator != null;
166 public IMemberContext MemberContext {
168 return member_context;
172 public ModuleContainer Module {
174 return member_context.Module;
178 // Has to be used for specific emitter errors only any
179 // possible resolver errors have to be reported during Resolve
180 public Report Report {
182 return member_context.Module.Compiler.Report;
186 public TypeSpec ReturnType {
193 // The label where we have to jump before leaving the context
195 public Label ReturnLabel {
197 return return_label.Value;
201 public List<IExpressionCleanup> StatementEpilogue {
203 return epilogue_expressions;
209 public void AddStatementEpilog (IExpressionCleanup cleanupExpression)
211 if (epilogue_expressions == null) {
212 epilogue_expressions = new List<IExpressionCleanup> ();
213 } else if (epilogue_expressions.Contains (cleanupExpression)) {
217 epilogue_expressions.Add (cleanupExpression);
220 public void AssertEmptyStack ()
223 if (ig.__StackHeight != 0)
224 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
225 member_context.GetSignatureForError ());
230 /// This is called immediately before emitting an IL opcode to tell the symbol
231 /// writer to which source line this opcode belongs.
233 public bool Mark (Location loc)
235 if ((flags & Options.OmitDebugInfo) != 0)
238 if (loc.IsNull || methodSymbols == null)
241 var sf = loc.SourceFile;
242 if (sf.IsHiddenLocation (loc))
246 methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
251 public void DefineLocalVariable (string name, LocalBuilder builder)
253 if ((flags & Options.OmitDebugInfo) != 0)
256 methodSymbols.AddLocal (builder.LocalIndex, name);
259 public void BeginCatchBlock (TypeSpec type)
261 ig.BeginCatchBlock (type.GetMetaInfo ());
264 public void BeginExceptionBlock ()
266 ig.BeginExceptionBlock ();
269 public void BeginFinallyBlock ()
271 ig.BeginFinallyBlock ();
274 public void BeginScope ()
276 if ((flags & Options.OmitDebugInfo) != 0)
280 methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
284 public void EndExceptionBlock ()
286 ig.EndExceptionBlock ();
289 public void EndScope ()
291 if ((flags & Options.OmitDebugInfo) != 0)
295 methodSymbols.EndBlock (ig.ILOffset);
300 // Creates a nested container in this context for all dynamic compiler generated stuff
302 internal DynamicSiteClass CreateDynamicSite ()
304 if (dynamic_site_container == null) {
305 var mc = member_context.CurrentMemberDefinition as MemberBase;
306 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
308 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
309 dynamic_site_container.CreateContainer ();
310 dynamic_site_container.DefineContainer ();
311 dynamic_site_container.Define ();
313 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
314 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
315 CurrentType.MemberCache.AddMember (inflated);
318 return dynamic_site_container;
321 public Label CreateReturnLabel ()
323 if (!return_label.HasValue)
324 return_label = DefineLabel ();
326 return return_label.Value;
329 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
331 if (IsAnonymousStoreyMutateRequired)
332 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
334 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
337 public Label DefineLabel ()
339 return ig.DefineLabel ();
343 // Creates temporary field in current async storey
345 public FieldExpr GetTemporaryField (TypeSpec type)
347 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
348 var fexpr = new StackFieldExpr (f);
349 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
353 public void MarkLabel (Label label)
355 ig.MarkLabel (label);
358 public void Emit (OpCode opcode)
363 public void Emit (OpCode opcode, LocalBuilder local)
365 ig.Emit (opcode, local);
368 public void Emit (OpCode opcode, string arg)
370 ig.Emit (opcode, arg);
373 public void Emit (OpCode opcode, double arg)
375 ig.Emit (opcode, arg);
378 public void Emit (OpCode opcode, float arg)
380 ig.Emit (opcode, arg);
383 public void Emit (OpCode opcode, Label label)
385 ig.Emit (opcode, label);
388 public void Emit (OpCode opcode, Label[] labels)
390 ig.Emit (opcode, labels);
393 public void Emit (OpCode opcode, TypeSpec type)
395 if (IsAnonymousStoreyMutateRequired)
396 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
398 ig.Emit (opcode, type.GetMetaInfo ());
401 public void Emit (OpCode opcode, FieldSpec field)
403 if (IsAnonymousStoreyMutateRequired)
404 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
406 ig.Emit (opcode, field.GetMetaInfo ());
409 public void Emit (OpCode opcode, MethodSpec method)
411 if (IsAnonymousStoreyMutateRequired)
412 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
414 if (method.IsConstructor)
415 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
417 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
420 // TODO: REMOVE breaks mutator
421 public void Emit (OpCode opcode, MethodInfo method)
423 ig.Emit (opcode, method);
426 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
428 // TODO MemberCache: This should mutate too
429 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
432 public void EmitArrayNew (ArrayContainer ac)
435 var type = IsAnonymousStoreyMutateRequired ?
436 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
439 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
441 if (IsAnonymousStoreyMutateRequired)
442 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
444 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
448 public void EmitArrayAddress (ArrayContainer ac)
451 if (IsAnonymousStoreyMutateRequired)
452 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
454 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
456 var type = IsAnonymousStoreyMutateRequired ?
457 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
460 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
465 // Emits the right opcode to load from an array
467 public void EmitArrayLoad (ArrayContainer ac)
470 if (IsAnonymousStoreyMutateRequired)
471 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
473 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
478 var type = ac.Element;
479 if (type.Kind == MemberKind.Enum)
480 type = EnumSpec.GetUnderlyingType (type);
482 switch (type.BuiltinType) {
483 case BuiltinTypeSpec.Type.Byte:
484 case BuiltinTypeSpec.Type.Bool:
485 ig.Emit (OpCodes.Ldelem_U1);
487 case BuiltinTypeSpec.Type.SByte:
488 ig.Emit (OpCodes.Ldelem_I1);
490 case BuiltinTypeSpec.Type.Short:
491 ig.Emit (OpCodes.Ldelem_I2);
493 case BuiltinTypeSpec.Type.UShort:
494 case BuiltinTypeSpec.Type.Char:
495 ig.Emit (OpCodes.Ldelem_U2);
497 case BuiltinTypeSpec.Type.Int:
498 ig.Emit (OpCodes.Ldelem_I4);
500 case BuiltinTypeSpec.Type.UInt:
501 ig.Emit (OpCodes.Ldelem_U4);
503 case BuiltinTypeSpec.Type.ULong:
504 case BuiltinTypeSpec.Type.Long:
505 ig.Emit (OpCodes.Ldelem_I8);
507 case BuiltinTypeSpec.Type.Float:
508 ig.Emit (OpCodes.Ldelem_R4);
510 case BuiltinTypeSpec.Type.Double:
511 ig.Emit (OpCodes.Ldelem_R8);
513 case BuiltinTypeSpec.Type.IntPtr:
514 ig.Emit (OpCodes.Ldelem_I);
518 case MemberKind.Struct:
519 if (IsAnonymousStoreyMutateRequired)
520 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
522 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
523 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
525 case MemberKind.TypeParameter:
526 if (IsAnonymousStoreyMutateRequired)
527 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
529 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
531 case MemberKind.PointerType:
532 ig.Emit (OpCodes.Ldelem_I);
535 ig.Emit (OpCodes.Ldelem_Ref);
543 // Emits the right opcode to store to an array
545 public void EmitArrayStore (ArrayContainer ac)
548 if (IsAnonymousStoreyMutateRequired)
549 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
551 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
555 var type = ac.Element;
557 if (type.Kind == MemberKind.Enum)
558 type = EnumSpec.GetUnderlyingType (type);
560 switch (type.BuiltinType) {
561 case BuiltinTypeSpec.Type.Byte:
562 case BuiltinTypeSpec.Type.SByte:
563 case BuiltinTypeSpec.Type.Bool:
564 Emit (OpCodes.Stelem_I1);
566 case BuiltinTypeSpec.Type.Short:
567 case BuiltinTypeSpec.Type.UShort:
568 case BuiltinTypeSpec.Type.Char:
569 Emit (OpCodes.Stelem_I2);
571 case BuiltinTypeSpec.Type.Int:
572 case BuiltinTypeSpec.Type.UInt:
573 Emit (OpCodes.Stelem_I4);
575 case BuiltinTypeSpec.Type.Long:
576 case BuiltinTypeSpec.Type.ULong:
577 Emit (OpCodes.Stelem_I8);
579 case BuiltinTypeSpec.Type.Float:
580 Emit (OpCodes.Stelem_R4);
582 case BuiltinTypeSpec.Type.Double:
583 Emit (OpCodes.Stelem_R8);
588 case MemberKind.Struct:
589 Emit (OpCodes.Stobj, type);
591 case MemberKind.TypeParameter:
592 Emit (OpCodes.Stelem, type);
594 case MemberKind.PointerType:
595 Emit (OpCodes.Stelem_I);
598 Emit (OpCodes.Stelem_Ref);
603 public void EmitInt (int i)
608 void EmitIntConstant (int i)
612 ig.Emit (OpCodes.Ldc_I4_M1);
616 ig.Emit (OpCodes.Ldc_I4_0);
620 ig.Emit (OpCodes.Ldc_I4_1);
624 ig.Emit (OpCodes.Ldc_I4_2);
628 ig.Emit (OpCodes.Ldc_I4_3);
632 ig.Emit (OpCodes.Ldc_I4_4);
636 ig.Emit (OpCodes.Ldc_I4_5);
640 ig.Emit (OpCodes.Ldc_I4_6);
644 ig.Emit (OpCodes.Ldc_I4_7);
648 ig.Emit (OpCodes.Ldc_I4_8);
652 if (i >= -128 && i <= 127) {
653 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
655 ig.Emit (OpCodes.Ldc_I4, i);
660 public void EmitLong (long l)
662 if (l >= int.MinValue && l <= int.MaxValue) {
663 EmitIntConstant (unchecked ((int) l));
664 ig.Emit (OpCodes.Conv_I8);
665 } else if (l >= 0 && l <= uint.MaxValue) {
666 EmitIntConstant (unchecked ((int) l));
667 ig.Emit (OpCodes.Conv_U8);
669 ig.Emit (OpCodes.Ldc_I8, l);
674 // Load the object from the pointer.
676 public void EmitLoadFromPtr (TypeSpec type)
678 if (type.Kind == MemberKind.Enum)
679 type = EnumSpec.GetUnderlyingType (type);
681 switch (type.BuiltinType) {
682 case BuiltinTypeSpec.Type.Int:
683 ig.Emit (OpCodes.Ldind_I4);
685 case BuiltinTypeSpec.Type.UInt:
686 ig.Emit (OpCodes.Ldind_U4);
688 case BuiltinTypeSpec.Type.Short:
689 ig.Emit (OpCodes.Ldind_I2);
691 case BuiltinTypeSpec.Type.UShort:
692 case BuiltinTypeSpec.Type.Char:
693 ig.Emit (OpCodes.Ldind_U2);
695 case BuiltinTypeSpec.Type.Byte:
696 ig.Emit (OpCodes.Ldind_U1);
698 case BuiltinTypeSpec.Type.SByte:
699 case BuiltinTypeSpec.Type.Bool:
700 ig.Emit (OpCodes.Ldind_I1);
702 case BuiltinTypeSpec.Type.ULong:
703 case BuiltinTypeSpec.Type.Long:
704 ig.Emit (OpCodes.Ldind_I8);
706 case BuiltinTypeSpec.Type.Float:
707 ig.Emit (OpCodes.Ldind_R4);
709 case BuiltinTypeSpec.Type.Double:
710 ig.Emit (OpCodes.Ldind_R8);
712 case BuiltinTypeSpec.Type.IntPtr:
713 ig.Emit (OpCodes.Ldind_I);
717 case MemberKind.Struct:
718 case MemberKind.TypeParameter:
719 if (IsAnonymousStoreyMutateRequired)
720 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
722 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
724 case MemberKind.PointerType:
725 ig.Emit (OpCodes.Ldind_I);
728 ig.Emit (OpCodes.Ldind_Ref);
735 public void EmitNull ()
737 ig.Emit (OpCodes.Ldnull);
740 public void EmitArgumentAddress (int pos)
745 if (pos > byte.MaxValue)
746 ig.Emit (OpCodes.Ldarga, pos);
748 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
751 public void EmitArgumentLoad (int pos)
757 case 0: ig.Emit (OpCodes.Ldarg_0); break;
758 case 1: ig.Emit (OpCodes.Ldarg_1); break;
759 case 2: ig.Emit (OpCodes.Ldarg_2); break;
760 case 3: ig.Emit (OpCodes.Ldarg_3); break;
762 if (pos > byte.MaxValue)
763 ig.Emit (OpCodes.Ldarg, pos);
765 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
770 public void EmitArgumentStore (int pos)
775 if (pos > byte.MaxValue)
776 ig.Emit (OpCodes.Starg, pos);
778 ig.Emit (OpCodes.Starg_S, (byte) pos);
782 // The stack contains the pointer and the value of type `type'
784 public void EmitStoreFromPtr (TypeSpec type)
787 type = EnumSpec.GetUnderlyingType (type);
789 switch (type.BuiltinType) {
790 case BuiltinTypeSpec.Type.Int:
791 case BuiltinTypeSpec.Type.UInt:
792 ig.Emit (OpCodes.Stind_I4);
794 case BuiltinTypeSpec.Type.Long:
795 case BuiltinTypeSpec.Type.ULong:
796 ig.Emit (OpCodes.Stind_I8);
798 case BuiltinTypeSpec.Type.Char:
799 case BuiltinTypeSpec.Type.Short:
800 case BuiltinTypeSpec.Type.UShort:
801 ig.Emit (OpCodes.Stind_I2);
803 case BuiltinTypeSpec.Type.Float:
804 ig.Emit (OpCodes.Stind_R4);
806 case BuiltinTypeSpec.Type.Double:
807 ig.Emit (OpCodes.Stind_R8);
809 case BuiltinTypeSpec.Type.Byte:
810 case BuiltinTypeSpec.Type.SByte:
811 case BuiltinTypeSpec.Type.Bool:
812 ig.Emit (OpCodes.Stind_I1);
814 case BuiltinTypeSpec.Type.IntPtr:
815 ig.Emit (OpCodes.Stind_I);
820 case MemberKind.Struct:
821 case MemberKind.TypeParameter:
822 if (IsAnonymousStoreyMutateRequired)
823 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
825 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
828 ig.Emit (OpCodes.Stind_Ref);
833 public void EmitThis ()
835 ig.Emit (OpCodes.Ldarg_0);
838 public void EmitEpilogue ()
840 if (epilogue_expressions == null)
843 foreach (var e in epilogue_expressions)
844 e.EmitCleanup (this);
846 epilogue_expressions = null;
850 /// Returns a temporary storage for a variable of type t as
851 /// a local variable in the current body.
853 public LocalBuilder GetTemporaryLocal (TypeSpec t)
855 if (temporary_storage != null) {
857 if (temporary_storage.TryGetValue (t, out o)) {
858 if (o is Stack<LocalBuilder>) {
859 var s = (Stack<LocalBuilder>) o;
860 o = s.Count == 0 ? null : s.Pop ();
862 temporary_storage.Remove (t);
866 return (LocalBuilder) o;
868 return DeclareLocal (t, false);
871 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
873 if (temporary_storage == null) {
874 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
875 temporary_storage.Add (t, b);
880 if (!temporary_storage.TryGetValue (t, out o)) {
881 temporary_storage.Add (t, b);
884 var s = o as Stack<LocalBuilder>;
886 s = new Stack<LocalBuilder> ();
887 s.Push ((LocalBuilder)o);
888 temporary_storage [t] = s;
894 /// ReturnValue creates on demand the LocalBuilder for the
895 /// return value from the function. By default this is not
896 /// used. This is only required when returns are found inside
897 /// Try or Catch statements.
899 /// This method is typically invoked from the Emit phase, so
900 /// we allow the creation of a return label if it was not
901 /// requested during the resolution phase. Could be cleaned
902 /// up, but it would replicate a lot of logic in the Emit phase
903 /// of the code that uses it.
905 public LocalBuilder TemporaryReturn ()
907 if (return_value == null){
908 return_value = DeclareLocal (return_type, false);
917 public Expression InstanceExpression;
920 // When set leaves an extra copy of all arguments on the stack
922 public bool DuplicateArguments;
925 // Does not emit InstanceExpression load when InstanceExpressionOnStack
926 // is set. Used by compound assignments.
928 public bool InstanceExpressionOnStack;
931 // Any of arguments contains await expression
933 public bool HasAwaitArguments;
936 // When dealing with await arguments the original arguments are converted
937 // into a new set with hoisted stack results
939 public Arguments EmittedArguments;
941 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
943 // Speed up the check by not doing it on not allowed targets
944 if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.MemberContext, loc))
947 EmitPredefined (ec, method, Arguments, loc);
950 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, Location? loc = null)
952 Expression instance_copy = null;
954 if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
955 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
956 if (HasAwaitArguments && InstanceExpressionOnStack) {
957 throw new NotSupportedException ();
962 LocalTemporary lt = null;
964 if (method.IsStatic) {
965 call_op = OpCodes.Call;
967 if (IsVirtualCallRequired (InstanceExpression, method)) {
968 call_op = OpCodes.Callvirt;
970 call_op = OpCodes.Call;
973 if (HasAwaitArguments) {
974 instance_copy = InstanceExpression.EmitToField (ec);
975 if (Arguments == null)
976 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
977 } else if (!InstanceExpressionOnStack) {
978 var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
980 if (DuplicateArguments) {
981 ec.Emit (OpCodes.Dup);
982 if (Arguments != null && Arguments.Count != 0) {
983 lt = new LocalTemporary (instance_on_stack_type);
991 if (Arguments != null && !InstanceExpressionOnStack) {
992 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
993 if (EmittedArguments != null) {
994 if (instance_copy != null) {
995 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
1001 EmittedArguments.Emit (ec);
1005 if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
1006 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
1011 // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
1012 // break at right place when LHS expression can be stepped-into
1014 // TODO: The list is probably not comprehensive, need to do more testing
1016 if (InstanceExpression is PropertyExpr || InstanceExpression is Invocation || InstanceExpression is IndexerExpr ||
1017 InstanceExpression is New || InstanceExpression is DelegateInvocation)
1018 ec.Mark (loc.Value);
1022 // Set instance expression to actual result expression. When it contains await it can be
1023 // picked up by caller
1025 InstanceExpression = instance_copy;
1027 if (method.Parameters.HasArglist) {
1028 var varargs_types = GetVarargsTypes (method, Arguments);
1029 ec.Emit (call_op, method, varargs_types);
1036 // and DoFoo is not virtual, you can omit the callvirt,
1037 // because you don't need the null checking behavior.
1039 ec.Emit (call_op, method);
1042 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
1044 var instance_type = instance.Type;
1047 // Push the instance expression
1049 if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1050 instance_type.IsGenericParameter || declaringType.IsNullableType) {
1052 // If the expression implements IMemoryLocation, then
1053 // we can optimize and use AddressOf on the
1056 // If not we have to use some temporary storage for
1058 var iml = instance as IMemoryLocation;
1060 iml.AddressOf (ec, AddressOp.Load);
1062 LocalTemporary temp = new LocalTemporary (instance_type);
1065 temp.AddressOf (ec, AddressOp.Load);
1068 return ReferenceContainer.MakeType (ec.Module, instance_type);
1071 if (instance_type.IsEnum || instance_type.IsStruct) {
1073 ec.Emit (OpCodes.Box, instance_type);
1074 return ec.BuiltinTypes.Object;
1078 return instance_type;
1081 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1083 AParametersCollection pd = method.Parameters;
1085 Argument a = arguments[pd.Count - 1];
1086 Arglist list = (Arglist) a.Expr;
1088 return list.ArgumentTypes;
1092 // Used to decide whether call or callvirt is needed
1094 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1097 // There are 2 scenarious where we emit callvirt
1099 // Case 1: A method is virtual and it's not used to call base
1100 // Case 2: A method instance expression can be null. In this casen callvirt ensures
1101 // correct NRE exception when the method is called
1103 var decl_type = method.DeclaringType;
1104 if (decl_type.IsStruct || decl_type.IsEnum)
1107 if (instance is BaseThis)
1111 // It's non-virtual and will never be null and it can be determined
1112 // whether it's known value or reference type by verifier
1114 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation) &&
1115 !instance.Type.IsGenericParameter)