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.
13 using System.Collections.Generic;
16 using MetaType = IKVM.Reflection.Type;
17 using IKVM.Reflection;
18 using IKVM.Reflection.Emit;
20 using MetaType = System.Type;
21 using System.Reflection;
22 using System.Reflection.Emit;
28 /// An Emit Context is created for each body of code (from methods,
29 /// properties bodies, indexer bodies or constructor bodies)
31 public class EmitContext : BuilderContext
33 // TODO: Has to be private
34 public readonly ILGenerator ig;
37 /// The value that is allowed to be returned or NULL if there is no
40 readonly TypeSpec return_type;
43 /// Keeps track of the Type to LocalBuilder temporary storage created
44 /// to store structures (used to compute the address of the structure
45 /// value on structure method invocations)
47 Dictionary<TypeSpec, object> temporary_storage;
50 /// The location where we store the return value.
52 public LocalBuilder return_value;
56 /// Current loop begin and end labels.
58 public Label LoopBegin, LoopEnd;
61 /// Default target in a switch statement. Only valid if
64 public Label DefaultTarget;
67 /// If this is non-null, points to the current switch statement
72 /// Whether we are inside an anonymous method.
74 public AnonymousExpression CurrentAnonymousMethod;
76 readonly IMemberContext member_context;
78 DynamicSiteClass dynamic_site_container;
82 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
84 this.member_context = rc;
86 this.return_type = return_type;
88 if (rc.Module.Compiler.Settings.Checked)
89 flags |= Options.CheckedScope;
92 ig.__CleverExceptionBlockAssistance ();
98 internal AsyncTaskStorey AsyncTaskStorey {
100 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
104 public BuiltinTypes BuiltinTypes {
106 return MemberContext.Module.Compiler.BuiltinTypes;
110 public TypeSpec CurrentType {
111 get { return member_context.CurrentType; }
114 public TypeParameter[] CurrentTypeParameters {
115 get { return member_context.CurrentTypeParameters; }
118 public MemberCore CurrentTypeDefinition {
119 get { return member_context.CurrentMemberDefinition; }
122 public bool HasReturnLabel {
124 return return_label.HasValue;
128 public bool IsStatic {
129 get { return member_context.IsStatic; }
132 public bool IsAnonymousStoreyMutateRequired {
134 return CurrentAnonymousMethod != null &&
135 CurrentAnonymousMethod.Storey != null &&
136 CurrentAnonymousMethod.Storey.Mutator != null;
140 public IMemberContext MemberContext {
142 return member_context;
146 public ModuleContainer Module {
148 return member_context.Module;
152 // Has to be used for specific emitter errors only any
153 // possible resolver errors have to be reported during Resolve
154 public Report Report {
156 return member_context.Module.Compiler.Report;
160 public TypeSpec ReturnType {
167 // The label where we have to jump before leaving the context
169 public Label ReturnLabel {
171 return return_label.Value;
177 public void AssertEmptyStack ()
180 if (ig.__StackHeight != 0)
181 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
182 member_context.GetSignatureForError ());
187 /// This is called immediately before emitting an IL opcode to tell the symbol
188 /// writer to which source line this opcode belongs.
190 public void Mark (Location loc)
192 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
195 SymbolWriter.MarkSequencePoint (ig, loc);
198 public void DefineLocalVariable (string name, LocalBuilder builder)
200 SymbolWriter.DefineLocalVariable (name, builder);
203 public void BeginCatchBlock (TypeSpec type)
205 ig.BeginCatchBlock (type.GetMetaInfo ());
208 public void BeginExceptionBlock ()
210 ig.BeginExceptionBlock ();
213 public void BeginFinallyBlock ()
215 ig.BeginFinallyBlock ();
218 public void BeginScope ()
220 SymbolWriter.OpenScope(ig);
223 public void EndExceptionBlock ()
225 ig.EndExceptionBlock ();
228 public void EndScope ()
230 SymbolWriter.CloseScope(ig);
234 // Creates a nested container in this context for all dynamic compiler generated stuff
236 internal DynamicSiteClass CreateDynamicSite ()
238 if (dynamic_site_container == null) {
239 var mc = member_context.CurrentMemberDefinition as MemberBase;
240 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
242 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
243 dynamic_site_container.CreateType ();
244 dynamic_site_container.DefineType ();
245 dynamic_site_container.ResolveTypeParameters ();
246 dynamic_site_container.Define ();
248 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
249 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
250 CurrentType.MemberCache.AddMember (inflated);
253 return dynamic_site_container;
256 public Label CreateReturnLabel ()
258 if (!return_label.HasValue)
259 return_label = DefineLabel ();
261 return return_label.Value;
264 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
266 if (IsAnonymousStoreyMutateRequired)
267 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
269 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
272 public Label DefineLabel ()
274 return ig.DefineLabel ();
278 // Creates temporary field in current async storey
280 public FieldExpr GetTemporaryField (TypeSpec type)
282 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
283 var fexpr = new FieldExpr (f, Location.Null);
284 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
288 public void MarkLabel (Label label)
290 ig.MarkLabel (label);
293 public void Emit (OpCode opcode)
298 public void Emit (OpCode opcode, LocalBuilder local)
300 ig.Emit (opcode, local);
303 public void Emit (OpCode opcode, string arg)
305 ig.Emit (opcode, arg);
308 public void Emit (OpCode opcode, double arg)
310 ig.Emit (opcode, arg);
313 public void Emit (OpCode opcode, float arg)
315 ig.Emit (opcode, arg);
318 public void Emit (OpCode opcode, Label label)
320 ig.Emit (opcode, label);
323 public void Emit (OpCode opcode, Label[] labels)
325 ig.Emit (opcode, labels);
328 public void Emit (OpCode opcode, TypeSpec type)
330 if (IsAnonymousStoreyMutateRequired)
331 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
333 ig.Emit (opcode, type.GetMetaInfo ());
336 public void Emit (OpCode opcode, FieldSpec field)
338 if (IsAnonymousStoreyMutateRequired)
339 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
341 ig.Emit (opcode, field.GetMetaInfo ());
344 public void Emit (OpCode opcode, MethodSpec method)
346 if (IsAnonymousStoreyMutateRequired)
347 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
349 if (method.IsConstructor)
350 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
352 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
355 // TODO: REMOVE breaks mutator
356 public void Emit (OpCode opcode, MethodInfo method)
358 ig.Emit (opcode, method);
361 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
363 // TODO MemberCache: This should mutate too
364 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
367 public void EmitArrayNew (ArrayContainer ac)
370 var type = IsAnonymousStoreyMutateRequired ?
371 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
374 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
376 if (IsAnonymousStoreyMutateRequired)
377 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
379 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
383 public void EmitArrayAddress (ArrayContainer ac)
386 if (IsAnonymousStoreyMutateRequired)
387 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
389 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
391 var type = IsAnonymousStoreyMutateRequired ?
392 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
395 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
400 // Emits the right opcode to load from an array
402 public void EmitArrayLoad (ArrayContainer ac)
405 if (IsAnonymousStoreyMutateRequired)
406 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
408 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
413 var type = ac.Element;
414 if (type.Kind == MemberKind.Enum)
415 type = EnumSpec.GetUnderlyingType (type);
417 switch (type.BuiltinType) {
418 case BuiltinTypeSpec.Type.Byte:
419 case BuiltinTypeSpec.Type.Bool:
420 ig.Emit (OpCodes.Ldelem_U1);
422 case BuiltinTypeSpec.Type.SByte:
423 ig.Emit (OpCodes.Ldelem_I1);
425 case BuiltinTypeSpec.Type.Short:
426 ig.Emit (OpCodes.Ldelem_I2);
428 case BuiltinTypeSpec.Type.UShort:
429 case BuiltinTypeSpec.Type.Char:
430 ig.Emit (OpCodes.Ldelem_U2);
432 case BuiltinTypeSpec.Type.Int:
433 ig.Emit (OpCodes.Ldelem_I4);
435 case BuiltinTypeSpec.Type.UInt:
436 ig.Emit (OpCodes.Ldelem_U4);
438 case BuiltinTypeSpec.Type.ULong:
439 case BuiltinTypeSpec.Type.Long:
440 ig.Emit (OpCodes.Ldelem_I8);
442 case BuiltinTypeSpec.Type.Float:
443 ig.Emit (OpCodes.Ldelem_R4);
445 case BuiltinTypeSpec.Type.Double:
446 ig.Emit (OpCodes.Ldelem_R8);
448 case BuiltinTypeSpec.Type.IntPtr:
449 ig.Emit (OpCodes.Ldelem_I);
453 case MemberKind.Struct:
454 if (IsAnonymousStoreyMutateRequired)
455 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
457 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
458 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
460 case MemberKind.TypeParameter:
461 if (IsAnonymousStoreyMutateRequired)
462 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
464 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
466 case MemberKind.PointerType:
467 ig.Emit (OpCodes.Ldelem_I);
470 ig.Emit (OpCodes.Ldelem_Ref);
478 // Emits the right opcode to store to an array
480 public void EmitArrayStore (ArrayContainer ac)
483 if (IsAnonymousStoreyMutateRequired)
484 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
486 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
490 var type = ac.Element;
492 if (type.Kind == MemberKind.Enum)
493 type = EnumSpec.GetUnderlyingType (type);
495 switch (type.BuiltinType) {
496 case BuiltinTypeSpec.Type.Byte:
497 case BuiltinTypeSpec.Type.SByte:
498 case BuiltinTypeSpec.Type.Bool:
499 Emit (OpCodes.Stelem_I1);
501 case BuiltinTypeSpec.Type.Short:
502 case BuiltinTypeSpec.Type.UShort:
503 case BuiltinTypeSpec.Type.Char:
504 Emit (OpCodes.Stelem_I2);
506 case BuiltinTypeSpec.Type.Int:
507 case BuiltinTypeSpec.Type.UInt:
508 Emit (OpCodes.Stelem_I4);
510 case BuiltinTypeSpec.Type.Long:
511 case BuiltinTypeSpec.Type.ULong:
512 Emit (OpCodes.Stelem_I8);
514 case BuiltinTypeSpec.Type.Float:
515 Emit (OpCodes.Stelem_R4);
517 case BuiltinTypeSpec.Type.Double:
518 Emit (OpCodes.Stelem_R8);
523 case MemberKind.Struct:
524 Emit (OpCodes.Stobj, type);
526 case MemberKind.TypeParameter:
527 Emit (OpCodes.Stelem, type);
529 case MemberKind.PointerType:
530 Emit (OpCodes.Stelem_I);
533 Emit (OpCodes.Stelem_Ref);
538 public void EmitInt (int i)
543 void EmitIntConstant (int i)
547 ig.Emit (OpCodes.Ldc_I4_M1);
551 ig.Emit (OpCodes.Ldc_I4_0);
555 ig.Emit (OpCodes.Ldc_I4_1);
559 ig.Emit (OpCodes.Ldc_I4_2);
563 ig.Emit (OpCodes.Ldc_I4_3);
567 ig.Emit (OpCodes.Ldc_I4_4);
571 ig.Emit (OpCodes.Ldc_I4_5);
575 ig.Emit (OpCodes.Ldc_I4_6);
579 ig.Emit (OpCodes.Ldc_I4_7);
583 ig.Emit (OpCodes.Ldc_I4_8);
587 if (i >= -128 && i <= 127) {
588 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
590 ig.Emit (OpCodes.Ldc_I4, i);
595 public void EmitLong (long l)
597 if (l >= int.MinValue && l <= int.MaxValue) {
598 EmitIntConstant (unchecked ((int) l));
599 ig.Emit (OpCodes.Conv_I8);
600 } else if (l >= 0 && l <= uint.MaxValue) {
601 EmitIntConstant (unchecked ((int) l));
602 ig.Emit (OpCodes.Conv_U8);
604 ig.Emit (OpCodes.Ldc_I8, l);
609 // Load the object from the pointer.
611 public void EmitLoadFromPtr (TypeSpec type)
613 if (type.Kind == MemberKind.Enum)
614 type = EnumSpec.GetUnderlyingType (type);
616 switch (type.BuiltinType) {
617 case BuiltinTypeSpec.Type.Int:
618 ig.Emit (OpCodes.Ldind_I4);
620 case BuiltinTypeSpec.Type.UInt:
621 ig.Emit (OpCodes.Ldind_U4);
623 case BuiltinTypeSpec.Type.Short:
624 ig.Emit (OpCodes.Ldind_I2);
626 case BuiltinTypeSpec.Type.UShort:
627 case BuiltinTypeSpec.Type.Char:
628 ig.Emit (OpCodes.Ldind_U2);
630 case BuiltinTypeSpec.Type.Byte:
631 ig.Emit (OpCodes.Ldind_U1);
633 case BuiltinTypeSpec.Type.SByte:
634 case BuiltinTypeSpec.Type.Bool:
635 ig.Emit (OpCodes.Ldind_I1);
637 case BuiltinTypeSpec.Type.ULong:
638 case BuiltinTypeSpec.Type.Long:
639 ig.Emit (OpCodes.Ldind_I8);
641 case BuiltinTypeSpec.Type.Float:
642 ig.Emit (OpCodes.Ldind_R4);
644 case BuiltinTypeSpec.Type.Double:
645 ig.Emit (OpCodes.Ldind_R8);
647 case BuiltinTypeSpec.Type.IntPtr:
648 ig.Emit (OpCodes.Ldind_I);
652 case MemberKind.Struct:
653 case MemberKind.TypeParameter:
654 if (IsAnonymousStoreyMutateRequired)
655 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
657 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
659 case MemberKind.PointerType:
660 ig.Emit (OpCodes.Ldind_I);
663 ig.Emit (OpCodes.Ldind_Ref);
670 public void EmitNull ()
672 ig.Emit (OpCodes.Ldnull);
675 public void EmitArgumentAddress (int pos)
680 if (pos > byte.MaxValue)
681 ig.Emit (OpCodes.Ldarga, pos);
683 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
686 public void EmitArgumentLoad (int pos)
692 case 0: ig.Emit (OpCodes.Ldarg_0); break;
693 case 1: ig.Emit (OpCodes.Ldarg_1); break;
694 case 2: ig.Emit (OpCodes.Ldarg_2); break;
695 case 3: ig.Emit (OpCodes.Ldarg_3); break;
697 if (pos > byte.MaxValue)
698 ig.Emit (OpCodes.Ldarg, pos);
700 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
705 public void EmitArgumentStore (int pos)
710 if (pos > byte.MaxValue)
711 ig.Emit (OpCodes.Starg, pos);
713 ig.Emit (OpCodes.Starg_S, (byte) pos);
717 // The stack contains the pointer and the value of type `type'
719 public void EmitStoreFromPtr (TypeSpec type)
722 type = EnumSpec.GetUnderlyingType (type);
724 switch (type.BuiltinType) {
725 case BuiltinTypeSpec.Type.Int:
726 case BuiltinTypeSpec.Type.UInt:
727 ig.Emit (OpCodes.Stind_I4);
729 case BuiltinTypeSpec.Type.Long:
730 case BuiltinTypeSpec.Type.ULong:
731 ig.Emit (OpCodes.Stind_I8);
733 case BuiltinTypeSpec.Type.Char:
734 case BuiltinTypeSpec.Type.Short:
735 case BuiltinTypeSpec.Type.UShort:
736 ig.Emit (OpCodes.Stind_I2);
738 case BuiltinTypeSpec.Type.Float:
739 ig.Emit (OpCodes.Stind_R4);
741 case BuiltinTypeSpec.Type.Double:
742 ig.Emit (OpCodes.Stind_R8);
744 case BuiltinTypeSpec.Type.Byte:
745 case BuiltinTypeSpec.Type.SByte:
746 case BuiltinTypeSpec.Type.Bool:
747 ig.Emit (OpCodes.Stind_I1);
749 case BuiltinTypeSpec.Type.IntPtr:
750 ig.Emit (OpCodes.Stind_I);
755 case MemberKind.Struct:
756 case MemberKind.TypeParameter:
757 if (IsAnonymousStoreyMutateRequired)
758 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
760 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
763 ig.Emit (OpCodes.Stind_Ref);
768 public void EmitThis ()
770 ig.Emit (OpCodes.Ldarg_0);
774 /// Returns a temporary storage for a variable of type t as
775 /// a local variable in the current body.
777 public LocalBuilder GetTemporaryLocal (TypeSpec t)
779 if (temporary_storage != null) {
781 if (temporary_storage.TryGetValue (t, out o)) {
782 if (o is Stack<LocalBuilder>) {
783 var s = (Stack<LocalBuilder>) o;
784 o = s.Count == 0 ? null : s.Pop ();
786 temporary_storage.Remove (t);
790 return (LocalBuilder) o;
792 return DeclareLocal (t, false);
795 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
797 if (temporary_storage == null) {
798 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
799 temporary_storage.Add (t, b);
804 if (!temporary_storage.TryGetValue (t, out o)) {
805 temporary_storage.Add (t, b);
808 var s = o as Stack<LocalBuilder>;
810 s = new Stack<LocalBuilder> ();
811 s.Push ((LocalBuilder)o);
812 temporary_storage [t] = s;
818 /// ReturnValue creates on demand the LocalBuilder for the
819 /// return value from the function. By default this is not
820 /// used. This is only required when returns are found inside
821 /// Try or Catch statements.
823 /// This method is typically invoked from the Emit phase, so
824 /// we allow the creation of a return label if it was not
825 /// requested during the resolution phase. Could be cleaned
826 /// up, but it would replicate a lot of logic in the Emit phase
827 /// of the code that uses it.
829 public LocalBuilder TemporaryReturn ()
831 if (return_value == null){
832 return_value = DeclareLocal (return_type, false);
841 public Expression InstanceExpression;
844 // When set leaves an extra copy of all arguments on the stack
846 public bool DuplicateArguments;
849 // Does not emit InstanceExpression load when InstanceExpressionOnStack
850 // is set. Used by compound assignments.
852 public bool InstanceExpressionOnStack;
855 // Any of arguments contains await expression
857 public bool HasAwaitArguments;
860 // When dealing with await arguments the original arguments are converted
861 // into a new set with hoisted stack results
863 public Arguments EmittedArguments;
865 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
867 // Speed up the check by not doing it on not allowed targets
868 if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.Module.Compiler, loc))
871 EmitPredefined (ec, method, Arguments);
874 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
876 Expression instance_copy = null;
878 if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
879 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
880 if (HasAwaitArguments && InstanceExpressionOnStack) {
881 throw new NotSupportedException ();
886 LocalTemporary lt = null;
888 if (method.IsStatic) {
889 call_op = OpCodes.Call;
891 if (IsVirtualCallRequired (InstanceExpression, method)) {
892 call_op = OpCodes.Callvirt;
894 call_op = OpCodes.Call;
897 if (HasAwaitArguments) {
898 instance_copy = InstanceExpression.EmitToField (ec);
899 if (Arguments == null)
900 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
901 } else if (!InstanceExpressionOnStack) {
902 var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
904 if (DuplicateArguments) {
905 ec.Emit (OpCodes.Dup);
906 if (Arguments != null && Arguments.Count != 0) {
907 lt = new LocalTemporary (instance_on_stack_type);
915 if (Arguments != null && !InstanceExpressionOnStack) {
916 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
917 if (EmittedArguments != null) {
918 if (instance_copy != null) {
919 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
925 EmittedArguments.Emit (ec);
929 if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
930 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
934 // Set instance expression to actual result expression. When it contains await it can be
935 // picked up by caller
937 InstanceExpression = instance_copy;
939 if (method.Parameters.HasArglist) {
940 var varargs_types = GetVarargsTypes (method, Arguments);
941 ec.Emit (call_op, method, varargs_types);
948 // and DoFoo is not virtual, you can omit the callvirt,
949 // because you don't need the null checking behavior.
951 ec.Emit (call_op, method);
954 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
956 var instance_type = instance.Type;
959 // Push the instance expression
961 if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType == instance_type))) ||
962 instance_type.IsGenericParameter || declaringType.IsNullableType) {
964 // If the expression implements IMemoryLocation, then
965 // we can optimize and use AddressOf on the
968 // If not we have to use some temporary storage for
970 var iml = instance as IMemoryLocation;
972 iml.AddressOf (ec, AddressOp.Load);
974 LocalTemporary temp = new LocalTemporary (instance_type);
977 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))