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;
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
19 using IKVM.Reflection.Emit;
21 using MetaType = System.Type;
22 using System.Reflection;
23 using System.Reflection.Emit;
29 /// An Emit Context is created for each body of code (from methods,
30 /// properties bodies, indexer bodies or constructor bodies)
32 public class EmitContext : BuilderContext
34 // TODO: Has to be private
35 public readonly ILGenerator ig;
38 /// The value that is allowed to be returned or NULL if there is no
41 readonly TypeSpec return_type;
44 /// Keeps track of the Type to LocalBuilder temporary storage created
45 /// to store structures (used to compute the address of the structure
46 /// value on structure method invocations)
48 Dictionary<TypeSpec, object> temporary_storage;
51 /// The location where we store the return value.
53 public LocalBuilder return_value;
57 /// Current loop begin and end labels.
59 public Label LoopBegin, LoopEnd;
62 /// Default target in a switch statement. Only valid if
65 public Label DefaultTarget;
68 /// If this is non-null, points to the current switch statement
73 /// Whether we are inside an anonymous method.
75 public AnonymousExpression CurrentAnonymousMethod;
77 readonly IMemberContext member_context;
79 DynamicSiteClass dynamic_site_container;
83 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
85 this.member_context = rc;
87 this.return_type = return_type;
89 if (rc.Module.Compiler.Settings.Checked)
90 flags |= Options.CheckedScope;
92 if (SymbolWriter.HasSymbolWriter) {
93 if (!rc.Module.Compiler.Settings.Optimize)
94 flags |= Options.AccurateDebugInfo;
96 flags |= Options.OmitDebugInfo;
100 ig.__CleverExceptionBlockAssistance ();
106 internal AsyncTaskStorey AsyncTaskStorey {
108 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
112 public BuiltinTypes BuiltinTypes {
114 return MemberContext.Module.Compiler.BuiltinTypes;
118 public TypeSpec CurrentType {
119 get { return member_context.CurrentType; }
122 public TypeParameters CurrentTypeParameters {
123 get { return member_context.CurrentTypeParameters; }
126 public MemberCore CurrentTypeDefinition {
127 get { return member_context.CurrentMemberDefinition; }
130 public bool EmitAccurateDebugInfo {
132 return (flags & Options.AccurateDebugInfo) != 0;
136 public bool HasReturnLabel {
138 return return_label.HasValue;
142 public bool IsStatic {
143 get { return member_context.IsStatic; }
146 public bool IsAnonymousStoreyMutateRequired {
148 return CurrentAnonymousMethod != null &&
149 CurrentAnonymousMethod.Storey != null &&
150 CurrentAnonymousMethod.Storey.Mutator != null;
154 public IMemberContext MemberContext {
156 return member_context;
160 public ModuleContainer Module {
162 return member_context.Module;
166 // Has to be used for specific emitter errors only any
167 // possible resolver errors have to be reported during Resolve
168 public Report Report {
170 return member_context.Module.Compiler.Report;
174 public TypeSpec ReturnType {
181 // The label where we have to jump before leaving the context
183 public Label ReturnLabel {
185 return return_label.Value;
191 public void AssertEmptyStack ()
194 if (ig.__StackHeight != 0)
195 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
196 member_context.GetSignatureForError ());
201 /// This is called immediately before emitting an IL opcode to tell the symbol
202 /// writer to which source line this opcode belongs.
204 public bool Mark (Location loc)
206 if ((flags & Options.OmitDebugInfo) != 0)
212 if (loc.SourceFile.IsHiddenLocation (loc))
215 SymbolWriter.MarkSequencePoint (ig, loc);
219 public void DefineLocalVariable (string name, LocalBuilder builder)
221 SymbolWriter.DefineLocalVariable (name, builder);
224 public void BeginCatchBlock (TypeSpec type)
226 ig.BeginCatchBlock (type.GetMetaInfo ());
229 public void BeginExceptionBlock ()
231 ig.BeginExceptionBlock ();
234 public void BeginFinallyBlock ()
236 ig.BeginFinallyBlock ();
239 public void BeginScope ()
241 SymbolWriter.OpenScope(ig);
244 public void EndExceptionBlock ()
246 ig.EndExceptionBlock ();
249 public void EndScope ()
251 SymbolWriter.CloseScope(ig);
255 // Creates a nested container in this context for all dynamic compiler generated stuff
257 internal DynamicSiteClass CreateDynamicSite ()
259 if (dynamic_site_container == null) {
260 var mc = member_context.CurrentMemberDefinition as MemberBase;
261 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
263 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
264 dynamic_site_container.CreateContainer ();
265 dynamic_site_container.DefineContainer ();
266 dynamic_site_container.Define ();
268 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
269 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
270 CurrentType.MemberCache.AddMember (inflated);
273 return dynamic_site_container;
276 public Label CreateReturnLabel ()
278 if (!return_label.HasValue)
279 return_label = DefineLabel ();
281 return return_label.Value;
284 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
286 if (IsAnonymousStoreyMutateRequired)
287 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
289 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
292 public Label DefineLabel ()
294 return ig.DefineLabel ();
298 // Creates temporary field in current async storey
300 public FieldExpr GetTemporaryField (TypeSpec type)
302 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
303 var fexpr = new StackFieldExpr (f);
304 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
308 public void MarkLabel (Label label)
310 ig.MarkLabel (label);
313 public void Emit (OpCode opcode)
318 public void Emit (OpCode opcode, LocalBuilder local)
320 ig.Emit (opcode, local);
323 public void Emit (OpCode opcode, string arg)
325 ig.Emit (opcode, arg);
328 public void Emit (OpCode opcode, double arg)
330 ig.Emit (opcode, arg);
333 public void Emit (OpCode opcode, float arg)
335 ig.Emit (opcode, arg);
338 public void Emit (OpCode opcode, Label label)
340 ig.Emit (opcode, label);
343 public void Emit (OpCode opcode, Label[] labels)
345 ig.Emit (opcode, labels);
348 public void Emit (OpCode opcode, TypeSpec type)
350 if (IsAnonymousStoreyMutateRequired)
351 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
353 ig.Emit (opcode, type.GetMetaInfo ());
356 public void Emit (OpCode opcode, FieldSpec field)
358 if (IsAnonymousStoreyMutateRequired)
359 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
361 ig.Emit (opcode, field.GetMetaInfo ());
364 public void Emit (OpCode opcode, MethodSpec method)
366 if (IsAnonymousStoreyMutateRequired)
367 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
369 if (method.IsConstructor)
370 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
372 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
375 // TODO: REMOVE breaks mutator
376 public void Emit (OpCode opcode, MethodInfo method)
378 ig.Emit (opcode, method);
381 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
383 // TODO MemberCache: This should mutate too
384 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
387 public void EmitArrayNew (ArrayContainer ac)
390 var type = IsAnonymousStoreyMutateRequired ?
391 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
394 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
396 if (IsAnonymousStoreyMutateRequired)
397 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
399 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
403 public void EmitArrayAddress (ArrayContainer ac)
406 if (IsAnonymousStoreyMutateRequired)
407 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
409 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
411 var type = IsAnonymousStoreyMutateRequired ?
412 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
415 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
420 // Emits the right opcode to load from an array
422 public void EmitArrayLoad (ArrayContainer ac)
425 if (IsAnonymousStoreyMutateRequired)
426 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
428 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
433 var type = ac.Element;
434 if (type.Kind == MemberKind.Enum)
435 type = EnumSpec.GetUnderlyingType (type);
437 switch (type.BuiltinType) {
438 case BuiltinTypeSpec.Type.Byte:
439 case BuiltinTypeSpec.Type.Bool:
440 ig.Emit (OpCodes.Ldelem_U1);
442 case BuiltinTypeSpec.Type.SByte:
443 ig.Emit (OpCodes.Ldelem_I1);
445 case BuiltinTypeSpec.Type.Short:
446 ig.Emit (OpCodes.Ldelem_I2);
448 case BuiltinTypeSpec.Type.UShort:
449 case BuiltinTypeSpec.Type.Char:
450 ig.Emit (OpCodes.Ldelem_U2);
452 case BuiltinTypeSpec.Type.Int:
453 ig.Emit (OpCodes.Ldelem_I4);
455 case BuiltinTypeSpec.Type.UInt:
456 ig.Emit (OpCodes.Ldelem_U4);
458 case BuiltinTypeSpec.Type.ULong:
459 case BuiltinTypeSpec.Type.Long:
460 ig.Emit (OpCodes.Ldelem_I8);
462 case BuiltinTypeSpec.Type.Float:
463 ig.Emit (OpCodes.Ldelem_R4);
465 case BuiltinTypeSpec.Type.Double:
466 ig.Emit (OpCodes.Ldelem_R8);
468 case BuiltinTypeSpec.Type.IntPtr:
469 ig.Emit (OpCodes.Ldelem_I);
473 case MemberKind.Struct:
474 if (IsAnonymousStoreyMutateRequired)
475 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
477 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
478 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
480 case MemberKind.TypeParameter:
481 if (IsAnonymousStoreyMutateRequired)
482 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
484 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
486 case MemberKind.PointerType:
487 ig.Emit (OpCodes.Ldelem_I);
490 ig.Emit (OpCodes.Ldelem_Ref);
498 // Emits the right opcode to store to an array
500 public void EmitArrayStore (ArrayContainer ac)
503 if (IsAnonymousStoreyMutateRequired)
504 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
506 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
510 var type = ac.Element;
512 if (type.Kind == MemberKind.Enum)
513 type = EnumSpec.GetUnderlyingType (type);
515 switch (type.BuiltinType) {
516 case BuiltinTypeSpec.Type.Byte:
517 case BuiltinTypeSpec.Type.SByte:
518 case BuiltinTypeSpec.Type.Bool:
519 Emit (OpCodes.Stelem_I1);
521 case BuiltinTypeSpec.Type.Short:
522 case BuiltinTypeSpec.Type.UShort:
523 case BuiltinTypeSpec.Type.Char:
524 Emit (OpCodes.Stelem_I2);
526 case BuiltinTypeSpec.Type.Int:
527 case BuiltinTypeSpec.Type.UInt:
528 Emit (OpCodes.Stelem_I4);
530 case BuiltinTypeSpec.Type.Long:
531 case BuiltinTypeSpec.Type.ULong:
532 Emit (OpCodes.Stelem_I8);
534 case BuiltinTypeSpec.Type.Float:
535 Emit (OpCodes.Stelem_R4);
537 case BuiltinTypeSpec.Type.Double:
538 Emit (OpCodes.Stelem_R8);
543 case MemberKind.Struct:
544 Emit (OpCodes.Stobj, type);
546 case MemberKind.TypeParameter:
547 Emit (OpCodes.Stelem, type);
549 case MemberKind.PointerType:
550 Emit (OpCodes.Stelem_I);
553 Emit (OpCodes.Stelem_Ref);
558 public void EmitInt (int i)
563 void EmitIntConstant (int i)
567 ig.Emit (OpCodes.Ldc_I4_M1);
571 ig.Emit (OpCodes.Ldc_I4_0);
575 ig.Emit (OpCodes.Ldc_I4_1);
579 ig.Emit (OpCodes.Ldc_I4_2);
583 ig.Emit (OpCodes.Ldc_I4_3);
587 ig.Emit (OpCodes.Ldc_I4_4);
591 ig.Emit (OpCodes.Ldc_I4_5);
595 ig.Emit (OpCodes.Ldc_I4_6);
599 ig.Emit (OpCodes.Ldc_I4_7);
603 ig.Emit (OpCodes.Ldc_I4_8);
607 if (i >= -128 && i <= 127) {
608 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
610 ig.Emit (OpCodes.Ldc_I4, i);
615 public void EmitLong (long l)
617 if (l >= int.MinValue && l <= int.MaxValue) {
618 EmitIntConstant (unchecked ((int) l));
619 ig.Emit (OpCodes.Conv_I8);
620 } else if (l >= 0 && l <= uint.MaxValue) {
621 EmitIntConstant (unchecked ((int) l));
622 ig.Emit (OpCodes.Conv_U8);
624 ig.Emit (OpCodes.Ldc_I8, l);
629 // Load the object from the pointer.
631 public void EmitLoadFromPtr (TypeSpec type)
633 if (type.Kind == MemberKind.Enum)
634 type = EnumSpec.GetUnderlyingType (type);
636 switch (type.BuiltinType) {
637 case BuiltinTypeSpec.Type.Int:
638 ig.Emit (OpCodes.Ldind_I4);
640 case BuiltinTypeSpec.Type.UInt:
641 ig.Emit (OpCodes.Ldind_U4);
643 case BuiltinTypeSpec.Type.Short:
644 ig.Emit (OpCodes.Ldind_I2);
646 case BuiltinTypeSpec.Type.UShort:
647 case BuiltinTypeSpec.Type.Char:
648 ig.Emit (OpCodes.Ldind_U2);
650 case BuiltinTypeSpec.Type.Byte:
651 ig.Emit (OpCodes.Ldind_U1);
653 case BuiltinTypeSpec.Type.SByte:
654 case BuiltinTypeSpec.Type.Bool:
655 ig.Emit (OpCodes.Ldind_I1);
657 case BuiltinTypeSpec.Type.ULong:
658 case BuiltinTypeSpec.Type.Long:
659 ig.Emit (OpCodes.Ldind_I8);
661 case BuiltinTypeSpec.Type.Float:
662 ig.Emit (OpCodes.Ldind_R4);
664 case BuiltinTypeSpec.Type.Double:
665 ig.Emit (OpCodes.Ldind_R8);
667 case BuiltinTypeSpec.Type.IntPtr:
668 ig.Emit (OpCodes.Ldind_I);
672 case MemberKind.Struct:
673 case MemberKind.TypeParameter:
674 if (IsAnonymousStoreyMutateRequired)
675 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
677 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
679 case MemberKind.PointerType:
680 ig.Emit (OpCodes.Ldind_I);
683 ig.Emit (OpCodes.Ldind_Ref);
690 public void EmitNull ()
692 ig.Emit (OpCodes.Ldnull);
695 public void EmitArgumentAddress (int pos)
700 if (pos > byte.MaxValue)
701 ig.Emit (OpCodes.Ldarga, pos);
703 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
706 public void EmitArgumentLoad (int pos)
712 case 0: ig.Emit (OpCodes.Ldarg_0); break;
713 case 1: ig.Emit (OpCodes.Ldarg_1); break;
714 case 2: ig.Emit (OpCodes.Ldarg_2); break;
715 case 3: ig.Emit (OpCodes.Ldarg_3); break;
717 if (pos > byte.MaxValue)
718 ig.Emit (OpCodes.Ldarg, pos);
720 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
725 public void EmitArgumentStore (int pos)
730 if (pos > byte.MaxValue)
731 ig.Emit (OpCodes.Starg, pos);
733 ig.Emit (OpCodes.Starg_S, (byte) pos);
737 // The stack contains the pointer and the value of type `type'
739 public void EmitStoreFromPtr (TypeSpec type)
742 type = EnumSpec.GetUnderlyingType (type);
744 switch (type.BuiltinType) {
745 case BuiltinTypeSpec.Type.Int:
746 case BuiltinTypeSpec.Type.UInt:
747 ig.Emit (OpCodes.Stind_I4);
749 case BuiltinTypeSpec.Type.Long:
750 case BuiltinTypeSpec.Type.ULong:
751 ig.Emit (OpCodes.Stind_I8);
753 case BuiltinTypeSpec.Type.Char:
754 case BuiltinTypeSpec.Type.Short:
755 case BuiltinTypeSpec.Type.UShort:
756 ig.Emit (OpCodes.Stind_I2);
758 case BuiltinTypeSpec.Type.Float:
759 ig.Emit (OpCodes.Stind_R4);
761 case BuiltinTypeSpec.Type.Double:
762 ig.Emit (OpCodes.Stind_R8);
764 case BuiltinTypeSpec.Type.Byte:
765 case BuiltinTypeSpec.Type.SByte:
766 case BuiltinTypeSpec.Type.Bool:
767 ig.Emit (OpCodes.Stind_I1);
769 case BuiltinTypeSpec.Type.IntPtr:
770 ig.Emit (OpCodes.Stind_I);
775 case MemberKind.Struct:
776 case MemberKind.TypeParameter:
777 if (IsAnonymousStoreyMutateRequired)
778 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
780 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
783 ig.Emit (OpCodes.Stind_Ref);
788 public void EmitThis ()
790 ig.Emit (OpCodes.Ldarg_0);
794 /// Returns a temporary storage for a variable of type t as
795 /// a local variable in the current body.
797 public LocalBuilder GetTemporaryLocal (TypeSpec t)
799 if (temporary_storage != null) {
801 if (temporary_storage.TryGetValue (t, out o)) {
802 if (o is Stack<LocalBuilder>) {
803 var s = (Stack<LocalBuilder>) o;
804 o = s.Count == 0 ? null : s.Pop ();
806 temporary_storage.Remove (t);
810 return (LocalBuilder) o;
812 return DeclareLocal (t, false);
815 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
817 if (temporary_storage == null) {
818 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
819 temporary_storage.Add (t, b);
824 if (!temporary_storage.TryGetValue (t, out o)) {
825 temporary_storage.Add (t, b);
828 var s = o as Stack<LocalBuilder>;
830 s = new Stack<LocalBuilder> ();
831 s.Push ((LocalBuilder)o);
832 temporary_storage [t] = s;
838 /// ReturnValue creates on demand the LocalBuilder for the
839 /// return value from the function. By default this is not
840 /// used. This is only required when returns are found inside
841 /// Try or Catch statements.
843 /// This method is typically invoked from the Emit phase, so
844 /// we allow the creation of a return label if it was not
845 /// requested during the resolution phase. Could be cleaned
846 /// up, but it would replicate a lot of logic in the Emit phase
847 /// of the code that uses it.
849 public LocalBuilder TemporaryReturn ()
851 if (return_value == null){
852 return_value = DeclareLocal (return_type, false);
861 public Expression InstanceExpression;
864 // When set leaves an extra copy of all arguments on the stack
866 public bool DuplicateArguments;
869 // Does not emit InstanceExpression load when InstanceExpressionOnStack
870 // is set. Used by compound assignments.
872 public bool InstanceExpressionOnStack;
875 // Any of arguments contains await expression
877 public bool HasAwaitArguments;
880 // When dealing with await arguments the original arguments are converted
881 // into a new set with hoisted stack results
883 public Arguments EmittedArguments;
885 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
887 // Speed up the check by not doing it on not allowed targets
888 if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.MemberContext, loc))
891 EmitPredefined (ec, method, Arguments);
894 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
896 Expression instance_copy = null;
898 if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
899 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
900 if (HasAwaitArguments && InstanceExpressionOnStack) {
901 throw new NotSupportedException ();
906 LocalTemporary lt = null;
908 if (method.IsStatic) {
909 call_op = OpCodes.Call;
911 if (IsVirtualCallRequired (InstanceExpression, method)) {
912 call_op = OpCodes.Callvirt;
914 call_op = OpCodes.Call;
917 if (HasAwaitArguments) {
918 instance_copy = InstanceExpression.EmitToField (ec);
919 if (Arguments == null)
920 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
921 } else if (!InstanceExpressionOnStack) {
922 var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
924 if (DuplicateArguments) {
925 ec.Emit (OpCodes.Dup);
926 if (Arguments != null && Arguments.Count != 0) {
927 lt = new LocalTemporary (instance_on_stack_type);
935 if (Arguments != null && !InstanceExpressionOnStack) {
936 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
937 if (EmittedArguments != null) {
938 if (instance_copy != null) {
939 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
945 EmittedArguments.Emit (ec);
949 if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
950 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
954 // Set instance expression to actual result expression. When it contains await it can be
955 // picked up by caller
957 InstanceExpression = instance_copy;
959 if (method.Parameters.HasArglist) {
960 var varargs_types = GetVarargsTypes (method, Arguments);
961 ec.Emit (call_op, method, varargs_types);
968 // and DoFoo is not virtual, you can omit the callvirt,
969 // because you don't need the null checking behavior.
971 ec.Emit (call_op, method);
974 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
976 var instance_type = instance.Type;
979 // Push the instance expression
981 if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
982 instance_type.IsGenericParameter || declaringType.IsNullableType) {
984 // If the expression implements IMemoryLocation, then
985 // we can optimize and use AddressOf on the
988 // If not we have to use some temporary storage for
990 var iml = instance as IMemoryLocation;
992 iml.AddressOf (ec, AddressOp.Load);
994 LocalTemporary temp = new LocalTemporary (instance_type);
997 temp.AddressOf (ec, AddressOp.Load);
1000 return ReferenceContainer.MakeType (ec.Module, instance_type);
1003 if (instance_type.IsEnum || instance_type.IsStruct) {
1005 ec.Emit (OpCodes.Box, instance_type);
1006 return ec.BuiltinTypes.Object;
1010 return instance_type;
1013 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1015 AParametersCollection pd = method.Parameters;
1017 Argument a = arguments[pd.Count - 1];
1018 Arglist list = (Arglist) a.Expr;
1020 return list.ArgumentTypes;
1024 // Used to decide whether call or callvirt is needed
1026 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1029 // There are 2 scenarious where we emit callvirt
1031 // Case 1: A method is virtual and it's not used to call base
1032 // Case 2: A method instance expression can be null. In this casen callvirt ensures
1033 // correct NRE exception when the method is called
1035 var decl_type = method.DeclaringType;
1036 if (decl_type.IsStruct || decl_type.IsEnum)
1039 if (instance is BaseThis)
1043 // It's non-virtual and will never be null
1045 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation))