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;
93 ig.__CleverExceptionBlockAssistance ();
99 internal AsyncTaskStorey AsyncTaskStorey {
101 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
105 public BuiltinTypes BuiltinTypes {
107 return MemberContext.Module.Compiler.BuiltinTypes;
111 public TypeSpec CurrentType {
112 get { return member_context.CurrentType; }
115 public TypeParameter[] CurrentTypeParameters {
116 get { return member_context.CurrentTypeParameters; }
119 public MemberCore CurrentTypeDefinition {
120 get { return member_context.CurrentMemberDefinition; }
123 public bool HasReturnLabel {
125 return return_label.HasValue;
129 public bool IsStatic {
130 get { return member_context.IsStatic; }
133 public bool IsAnonymousStoreyMutateRequired {
135 return CurrentAnonymousMethod != null &&
136 CurrentAnonymousMethod.Storey != null &&
137 CurrentAnonymousMethod.Storey.Mutator != null;
141 public IMemberContext MemberContext {
143 return member_context;
147 public ModuleContainer Module {
149 return member_context.Module;
153 // Has to be used for specific emitter errors only any
154 // possible resolver errors have to be reported during Resolve
155 public Report Report {
157 return member_context.Module.Compiler.Report;
161 public TypeSpec ReturnType {
168 // The label where we have to jump before leaving the context
170 public Label ReturnLabel {
172 return return_label.Value;
178 public void AssertEmptyStack ()
181 if (ig.__StackHeight != 0)
182 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
183 member_context.GetSignatureForError ());
188 /// This is called immediately before emitting an IL opcode to tell the symbol
189 /// writer to which source line this opcode belongs.
191 public void Mark (Location loc)
193 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
196 SymbolWriter.MarkSequencePoint (ig, loc);
199 public void DefineLocalVariable (string name, LocalBuilder builder)
201 SymbolWriter.DefineLocalVariable (name, builder);
204 public void BeginCatchBlock (TypeSpec type)
206 ig.BeginCatchBlock (type.GetMetaInfo ());
209 public void BeginExceptionBlock ()
211 ig.BeginExceptionBlock ();
214 public void BeginFinallyBlock ()
216 ig.BeginFinallyBlock ();
219 public void BeginScope ()
221 SymbolWriter.OpenScope(ig);
224 public void EndExceptionBlock ()
226 ig.EndExceptionBlock ();
229 public void EndScope ()
231 SymbolWriter.CloseScope(ig);
235 // Creates a nested container in this context for all dynamic compiler generated stuff
237 internal DynamicSiteClass CreateDynamicSite ()
239 if (dynamic_site_container == null) {
240 var mc = member_context.CurrentMemberDefinition as MemberBase;
241 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
243 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
244 dynamic_site_container.CreateType ();
245 dynamic_site_container.DefineType ();
246 dynamic_site_container.ResolveTypeParameters ();
247 dynamic_site_container.Define ();
249 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
250 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
251 CurrentType.MemberCache.AddMember (inflated);
254 return dynamic_site_container;
257 public Label CreateReturnLabel ()
259 if (!return_label.HasValue)
260 return_label = DefineLabel ();
262 return return_label.Value;
265 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
267 if (IsAnonymousStoreyMutateRequired)
268 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
270 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
273 public Label DefineLabel ()
275 return ig.DefineLabel ();
279 // Creates temporary field in current async storey
281 public FieldExpr GetTemporaryField (TypeSpec type)
283 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
284 var fexpr = new StackFieldExpr (f);
285 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
289 public void MarkLabel (Label label)
291 ig.MarkLabel (label);
294 public void Emit (OpCode opcode)
299 public void Emit (OpCode opcode, LocalBuilder local)
301 ig.Emit (opcode, local);
304 public void Emit (OpCode opcode, string arg)
306 ig.Emit (opcode, arg);
309 public void Emit (OpCode opcode, double arg)
311 ig.Emit (opcode, arg);
314 public void Emit (OpCode opcode, float arg)
316 ig.Emit (opcode, arg);
319 public void Emit (OpCode opcode, Label label)
321 ig.Emit (opcode, label);
324 public void Emit (OpCode opcode, Label[] labels)
326 ig.Emit (opcode, labels);
329 public void Emit (OpCode opcode, TypeSpec type)
331 if (IsAnonymousStoreyMutateRequired)
332 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
334 ig.Emit (opcode, type.GetMetaInfo ());
337 public void Emit (OpCode opcode, FieldSpec field)
339 if (IsAnonymousStoreyMutateRequired)
340 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
342 ig.Emit (opcode, field.GetMetaInfo ());
345 public void Emit (OpCode opcode, MethodSpec method)
347 if (IsAnonymousStoreyMutateRequired)
348 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
350 if (method.IsConstructor)
351 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
353 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
356 // TODO: REMOVE breaks mutator
357 public void Emit (OpCode opcode, MethodInfo method)
359 ig.Emit (opcode, method);
362 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
364 // TODO MemberCache: This should mutate too
365 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
368 public void EmitArrayNew (ArrayContainer ac)
371 var type = IsAnonymousStoreyMutateRequired ?
372 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
375 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
377 if (IsAnonymousStoreyMutateRequired)
378 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
380 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
384 public void EmitArrayAddress (ArrayContainer ac)
387 if (IsAnonymousStoreyMutateRequired)
388 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
390 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
392 var type = IsAnonymousStoreyMutateRequired ?
393 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
396 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
401 // Emits the right opcode to load from an array
403 public void EmitArrayLoad (ArrayContainer ac)
406 if (IsAnonymousStoreyMutateRequired)
407 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
409 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
414 var type = ac.Element;
415 if (type.Kind == MemberKind.Enum)
416 type = EnumSpec.GetUnderlyingType (type);
418 switch (type.BuiltinType) {
419 case BuiltinTypeSpec.Type.Byte:
420 case BuiltinTypeSpec.Type.Bool:
421 ig.Emit (OpCodes.Ldelem_U1);
423 case BuiltinTypeSpec.Type.SByte:
424 ig.Emit (OpCodes.Ldelem_I1);
426 case BuiltinTypeSpec.Type.Short:
427 ig.Emit (OpCodes.Ldelem_I2);
429 case BuiltinTypeSpec.Type.UShort:
430 case BuiltinTypeSpec.Type.Char:
431 ig.Emit (OpCodes.Ldelem_U2);
433 case BuiltinTypeSpec.Type.Int:
434 ig.Emit (OpCodes.Ldelem_I4);
436 case BuiltinTypeSpec.Type.UInt:
437 ig.Emit (OpCodes.Ldelem_U4);
439 case BuiltinTypeSpec.Type.ULong:
440 case BuiltinTypeSpec.Type.Long:
441 ig.Emit (OpCodes.Ldelem_I8);
443 case BuiltinTypeSpec.Type.Float:
444 ig.Emit (OpCodes.Ldelem_R4);
446 case BuiltinTypeSpec.Type.Double:
447 ig.Emit (OpCodes.Ldelem_R8);
449 case BuiltinTypeSpec.Type.IntPtr:
450 ig.Emit (OpCodes.Ldelem_I);
454 case MemberKind.Struct:
455 if (IsAnonymousStoreyMutateRequired)
456 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
458 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
459 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
461 case MemberKind.TypeParameter:
462 if (IsAnonymousStoreyMutateRequired)
463 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
465 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
467 case MemberKind.PointerType:
468 ig.Emit (OpCodes.Ldelem_I);
471 ig.Emit (OpCodes.Ldelem_Ref);
479 // Emits the right opcode to store to an array
481 public void EmitArrayStore (ArrayContainer ac)
484 if (IsAnonymousStoreyMutateRequired)
485 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
487 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
491 var type = ac.Element;
493 if (type.Kind == MemberKind.Enum)
494 type = EnumSpec.GetUnderlyingType (type);
496 switch (type.BuiltinType) {
497 case BuiltinTypeSpec.Type.Byte:
498 case BuiltinTypeSpec.Type.SByte:
499 case BuiltinTypeSpec.Type.Bool:
500 Emit (OpCodes.Stelem_I1);
502 case BuiltinTypeSpec.Type.Short:
503 case BuiltinTypeSpec.Type.UShort:
504 case BuiltinTypeSpec.Type.Char:
505 Emit (OpCodes.Stelem_I2);
507 case BuiltinTypeSpec.Type.Int:
508 case BuiltinTypeSpec.Type.UInt:
509 Emit (OpCodes.Stelem_I4);
511 case BuiltinTypeSpec.Type.Long:
512 case BuiltinTypeSpec.Type.ULong:
513 Emit (OpCodes.Stelem_I8);
515 case BuiltinTypeSpec.Type.Float:
516 Emit (OpCodes.Stelem_R4);
518 case BuiltinTypeSpec.Type.Double:
519 Emit (OpCodes.Stelem_R8);
524 case MemberKind.Struct:
525 Emit (OpCodes.Stobj, type);
527 case MemberKind.TypeParameter:
528 Emit (OpCodes.Stelem, type);
530 case MemberKind.PointerType:
531 Emit (OpCodes.Stelem_I);
534 Emit (OpCodes.Stelem_Ref);
539 public void EmitInt (int i)
544 void EmitIntConstant (int i)
548 ig.Emit (OpCodes.Ldc_I4_M1);
552 ig.Emit (OpCodes.Ldc_I4_0);
556 ig.Emit (OpCodes.Ldc_I4_1);
560 ig.Emit (OpCodes.Ldc_I4_2);
564 ig.Emit (OpCodes.Ldc_I4_3);
568 ig.Emit (OpCodes.Ldc_I4_4);
572 ig.Emit (OpCodes.Ldc_I4_5);
576 ig.Emit (OpCodes.Ldc_I4_6);
580 ig.Emit (OpCodes.Ldc_I4_7);
584 ig.Emit (OpCodes.Ldc_I4_8);
588 if (i >= -128 && i <= 127) {
589 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
591 ig.Emit (OpCodes.Ldc_I4, i);
596 public void EmitLong (long l)
598 if (l >= int.MinValue && l <= int.MaxValue) {
599 EmitIntConstant (unchecked ((int) l));
600 ig.Emit (OpCodes.Conv_I8);
601 } else if (l >= 0 && l <= uint.MaxValue) {
602 EmitIntConstant (unchecked ((int) l));
603 ig.Emit (OpCodes.Conv_U8);
605 ig.Emit (OpCodes.Ldc_I8, l);
610 // Load the object from the pointer.
612 public void EmitLoadFromPtr (TypeSpec type)
614 if (type.Kind == MemberKind.Enum)
615 type = EnumSpec.GetUnderlyingType (type);
617 switch (type.BuiltinType) {
618 case BuiltinTypeSpec.Type.Int:
619 ig.Emit (OpCodes.Ldind_I4);
621 case BuiltinTypeSpec.Type.UInt:
622 ig.Emit (OpCodes.Ldind_U4);
624 case BuiltinTypeSpec.Type.Short:
625 ig.Emit (OpCodes.Ldind_I2);
627 case BuiltinTypeSpec.Type.UShort:
628 case BuiltinTypeSpec.Type.Char:
629 ig.Emit (OpCodes.Ldind_U2);
631 case BuiltinTypeSpec.Type.Byte:
632 ig.Emit (OpCodes.Ldind_U1);
634 case BuiltinTypeSpec.Type.SByte:
635 case BuiltinTypeSpec.Type.Bool:
636 ig.Emit (OpCodes.Ldind_I1);
638 case BuiltinTypeSpec.Type.ULong:
639 case BuiltinTypeSpec.Type.Long:
640 ig.Emit (OpCodes.Ldind_I8);
642 case BuiltinTypeSpec.Type.Float:
643 ig.Emit (OpCodes.Ldind_R4);
645 case BuiltinTypeSpec.Type.Double:
646 ig.Emit (OpCodes.Ldind_R8);
648 case BuiltinTypeSpec.Type.IntPtr:
649 ig.Emit (OpCodes.Ldind_I);
653 case MemberKind.Struct:
654 case MemberKind.TypeParameter:
655 if (IsAnonymousStoreyMutateRequired)
656 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
658 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
660 case MemberKind.PointerType:
661 ig.Emit (OpCodes.Ldind_I);
664 ig.Emit (OpCodes.Ldind_Ref);
671 public void EmitNull ()
673 ig.Emit (OpCodes.Ldnull);
676 public void EmitArgumentAddress (int pos)
681 if (pos > byte.MaxValue)
682 ig.Emit (OpCodes.Ldarga, pos);
684 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
687 public void EmitArgumentLoad (int pos)
693 case 0: ig.Emit (OpCodes.Ldarg_0); break;
694 case 1: ig.Emit (OpCodes.Ldarg_1); break;
695 case 2: ig.Emit (OpCodes.Ldarg_2); break;
696 case 3: ig.Emit (OpCodes.Ldarg_3); break;
698 if (pos > byte.MaxValue)
699 ig.Emit (OpCodes.Ldarg, pos);
701 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
706 public void EmitArgumentStore (int pos)
711 if (pos > byte.MaxValue)
712 ig.Emit (OpCodes.Starg, pos);
714 ig.Emit (OpCodes.Starg_S, (byte) pos);
718 // The stack contains the pointer and the value of type `type'
720 public void EmitStoreFromPtr (TypeSpec type)
723 type = EnumSpec.GetUnderlyingType (type);
725 switch (type.BuiltinType) {
726 case BuiltinTypeSpec.Type.Int:
727 case BuiltinTypeSpec.Type.UInt:
728 ig.Emit (OpCodes.Stind_I4);
730 case BuiltinTypeSpec.Type.Long:
731 case BuiltinTypeSpec.Type.ULong:
732 ig.Emit (OpCodes.Stind_I8);
734 case BuiltinTypeSpec.Type.Char:
735 case BuiltinTypeSpec.Type.Short:
736 case BuiltinTypeSpec.Type.UShort:
737 ig.Emit (OpCodes.Stind_I2);
739 case BuiltinTypeSpec.Type.Float:
740 ig.Emit (OpCodes.Stind_R4);
742 case BuiltinTypeSpec.Type.Double:
743 ig.Emit (OpCodes.Stind_R8);
745 case BuiltinTypeSpec.Type.Byte:
746 case BuiltinTypeSpec.Type.SByte:
747 case BuiltinTypeSpec.Type.Bool:
748 ig.Emit (OpCodes.Stind_I1);
750 case BuiltinTypeSpec.Type.IntPtr:
751 ig.Emit (OpCodes.Stind_I);
756 case MemberKind.Struct:
757 case MemberKind.TypeParameter:
758 if (IsAnonymousStoreyMutateRequired)
759 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
761 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
764 ig.Emit (OpCodes.Stind_Ref);
769 public void EmitThis ()
771 ig.Emit (OpCodes.Ldarg_0);
775 /// Returns a temporary storage for a variable of type t as
776 /// a local variable in the current body.
778 public LocalBuilder GetTemporaryLocal (TypeSpec t)
780 if (temporary_storage != null) {
782 if (temporary_storage.TryGetValue (t, out o)) {
783 if (o is Stack<LocalBuilder>) {
784 var s = (Stack<LocalBuilder>) o;
785 o = s.Count == 0 ? null : s.Pop ();
787 temporary_storage.Remove (t);
791 return (LocalBuilder) o;
793 return DeclareLocal (t, false);
796 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
798 if (temporary_storage == null) {
799 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
800 temporary_storage.Add (t, b);
805 if (!temporary_storage.TryGetValue (t, out o)) {
806 temporary_storage.Add (t, b);
809 var s = o as Stack<LocalBuilder>;
811 s = new Stack<LocalBuilder> ();
812 s.Push ((LocalBuilder)o);
813 temporary_storage [t] = s;
819 /// ReturnValue creates on demand the LocalBuilder for the
820 /// return value from the function. By default this is not
821 /// used. This is only required when returns are found inside
822 /// Try or Catch statements.
824 /// This method is typically invoked from the Emit phase, so
825 /// we allow the creation of a return label if it was not
826 /// requested during the resolution phase. Could be cleaned
827 /// up, but it would replicate a lot of logic in the Emit phase
828 /// of the code that uses it.
830 public LocalBuilder TemporaryReturn ()
832 if (return_value == null){
833 return_value = DeclareLocal (return_type, false);
842 public Expression InstanceExpression;
845 // When set leaves an extra copy of all arguments on the stack
847 public bool DuplicateArguments;
850 // Does not emit InstanceExpression load when InstanceExpressionOnStack
851 // is set. Used by compound assignments.
853 public bool InstanceExpressionOnStack;
856 // Any of arguments contains await expression
858 public bool HasAwaitArguments;
861 // When dealing with await arguments the original arguments are converted
862 // into a new set with hoisted stack results
864 public Arguments EmittedArguments;
866 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
868 // Speed up the check by not doing it on not allowed targets
869 if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.Module.Compiler, loc))
872 EmitPredefined (ec, method, Arguments);
875 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
877 Expression instance_copy = null;
879 if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
880 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
881 if (HasAwaitArguments && InstanceExpressionOnStack) {
882 throw new NotSupportedException ();
887 LocalTemporary lt = null;
889 if (method.IsStatic) {
890 call_op = OpCodes.Call;
892 if (IsVirtualCallRequired (InstanceExpression, method)) {
893 call_op = OpCodes.Callvirt;
895 call_op = OpCodes.Call;
898 if (HasAwaitArguments) {
899 instance_copy = InstanceExpression.EmitToField (ec);
900 if (Arguments == null)
901 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
902 } else if (!InstanceExpressionOnStack) {
903 var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
905 if (DuplicateArguments) {
906 ec.Emit (OpCodes.Dup);
907 if (Arguments != null && Arguments.Count != 0) {
908 lt = new LocalTemporary (instance_on_stack_type);
916 if (Arguments != null && !InstanceExpressionOnStack) {
917 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
918 if (EmittedArguments != null) {
919 if (instance_copy != null) {
920 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
926 EmittedArguments.Emit (ec);
930 if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
931 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
935 // Set instance expression to actual result expression. When it contains await it can be
936 // picked up by caller
938 InstanceExpression = instance_copy;
940 if (method.Parameters.HasArglist) {
941 var varargs_types = GetVarargsTypes (method, Arguments);
942 ec.Emit (call_op, method, varargs_types);
949 // and DoFoo is not virtual, you can omit the callvirt,
950 // because you don't need the null checking behavior.
952 ec.Emit (call_op, method);
955 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
957 var instance_type = instance.Type;
960 // Push the instance expression
962 if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
963 instance_type.IsGenericParameter || declaringType.IsNullableType) {
965 // If the expression implements IMemoryLocation, then
966 // we can optimize and use AddressOf on the
969 // If not we have to use some temporary storage for
971 var iml = instance as IMemoryLocation;
973 iml.AddressOf (ec, AddressOp.Load);
975 LocalTemporary temp = new LocalTemporary (instance_type);
978 temp.AddressOf (ec, AddressOp.Load);
981 return ReferenceContainer.MakeType (ec.Module, instance_type);
984 if (instance_type.IsEnum || instance_type.IsStruct) {
986 ec.Emit (OpCodes.Box, instance_type);
987 return ec.BuiltinTypes.Object;
991 return instance_type;
994 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
996 AParametersCollection pd = method.Parameters;
998 Argument a = arguments[pd.Count - 1];
999 Arglist list = (Arglist) a.Expr;
1001 return list.ArgumentTypes;
1005 // Used to decide whether call or callvirt is needed
1007 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1010 // There are 2 scenarious where we emit callvirt
1012 // Case 1: A method is virtual and it's not used to call base
1013 // Case 2: A method instance expression can be null. In this casen callvirt ensures
1014 // correct NRE exception when the method is called
1016 var decl_type = method.DeclaringType;
1017 if (decl_type.IsStruct || decl_type.IsEnum)
1020 if (instance is BaseThis)
1024 // It's non-virtual and will never be null
1026 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation))