Added tests for Task.WhenAll w/ empty list
[mono.git] / mcs / mcs / codegen.cs
1 //
2 // codegen.cs: The code generator
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using Mono.CompilerServices.SymbolWriter;
16
17 #if STATIC
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
21 #else
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
25 #endif
26
27 namespace Mono.CSharp
28 {
29         /// <summary>
30         ///   An Emit Context is created for each body of code (from methods,
31         ///   properties bodies, indexer bodies or constructor bodies)
32         /// </summary>
33         public class EmitContext : BuilderContext
34         {
35                 // TODO: Has to be private
36                 public readonly ILGenerator ig;
37
38                 /// <summary>
39                 ///   The value that is allowed to be returned or NULL if there is no
40                 ///   return type.
41                 /// </summary>
42                 readonly TypeSpec return_type;
43
44                 /// <summary>
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)
48                 /// </summary>
49                 Dictionary<TypeSpec, object> temporary_storage;
50
51                 /// <summary>
52                 ///   The location where we store the return value.
53                 /// </summary>
54                 public LocalBuilder return_value;
55
56
57                 /// <summary>
58                 ///   Current loop begin and end labels.
59                 /// </summary>
60                 public Label LoopBegin, LoopEnd;
61
62                 /// <summary>
63                 ///   Default target in a switch statement.   Only valid if
64                 ///   InSwitch is true
65                 /// </summary>
66                 public Label DefaultTarget;
67
68                 /// <summary>
69                 ///   If this is non-null, points to the current switch statement
70                 /// </summary>
71                 public Switch Switch;
72
73                 /// <summary>
74                 ///  Whether we are inside an anonymous method.
75                 /// </summary>
76                 public AnonymousExpression CurrentAnonymousMethod;
77                 
78                 readonly IMemberContext member_context;
79
80                 readonly SourceMethodBuilder methodSymbols;
81
82                 DynamicSiteClass dynamic_site_container;
83
84                 Label? return_label;
85
86                 List<IExpressionCleanup> epilogue_expressions;
87
88                 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type, SourceMethodBuilder methodSymbols)
89                 {
90                         this.member_context = rc;
91                         this.ig = ig;
92                         this.return_type = return_type;
93
94                         if (rc.Module.Compiler.Settings.Checked)
95                                 flags |= Options.CheckedScope;
96
97                         if (methodSymbols != null) {
98                                 this.methodSymbols = methodSymbols;
99                                 if (!rc.Module.Compiler.Settings.Optimize)
100                                         flags |= Options.AccurateDebugInfo;
101                         } else {
102                                 flags |= Options.OmitDebugInfo;
103                         }
104
105 #if STATIC
106                         ig.__CleverExceptionBlockAssistance ();
107 #endif
108                 }
109
110                 #region Properties
111
112                 internal AsyncTaskStorey AsyncTaskStorey {
113                         get {
114                                 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
115                         }
116                 }
117
118                 public BuiltinTypes BuiltinTypes {
119                         get {
120                                 return MemberContext.Module.Compiler.BuiltinTypes;
121                         }
122                 }
123
124                 public TypeSpec CurrentType {
125                         get { return member_context.CurrentType; }
126                 }
127
128                 public TypeParameters CurrentTypeParameters {
129                     get { return member_context.CurrentTypeParameters; }
130                 }
131
132                 public MemberCore CurrentTypeDefinition {
133                         get { return member_context.CurrentMemberDefinition; }
134                 }
135
136                 public bool EmitAccurateDebugInfo {
137                         get {
138                                 return (flags & Options.AccurateDebugInfo) != 0;
139                         }
140                 }
141
142                 public bool HasMethodSymbolBuilder {
143                         get {
144                                 return methodSymbols != null;
145                         }
146                 }
147
148                 public bool HasReturnLabel {
149                         get {
150                                 return return_label.HasValue;
151                         }
152                 }
153
154                 public bool IsStatic {
155                         get { return member_context.IsStatic; }
156                 }
157
158                 public bool IsAnonymousStoreyMutateRequired {
159                         get {
160                                 return CurrentAnonymousMethod != null &&
161                                         CurrentAnonymousMethod.Storey != null &&
162                                         CurrentAnonymousMethod.Storey.Mutator != null;
163                         }
164                 }
165
166                 public IMemberContext MemberContext {
167                         get {
168                                 return member_context;
169                         }
170                 }
171
172                 public ModuleContainer Module {
173                         get {
174                                 return member_context.Module;
175                         }
176                 }
177
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 {
181                         get {
182                                 return member_context.Module.Compiler.Report;
183                         }
184                 }
185
186                 public TypeSpec ReturnType {
187                         get {
188                                 return return_type;
189                         }
190                 }
191
192                 //
193                 // The label where we have to jump before leaving the context
194                 //
195                 public Label ReturnLabel {
196                         get {
197                                 return return_label.Value;
198                         }
199                 }
200
201                 public List<IExpressionCleanup> StatementEpilogue {
202                         get {
203                                 return epilogue_expressions;
204                         }
205                 }
206
207                 #endregion
208
209                 public void AddStatementEpilog (IExpressionCleanup cleanupExpression)
210                 {
211                         if (epilogue_expressions == null) {
212                                 epilogue_expressions = new List<IExpressionCleanup> ();
213                         } else if (epilogue_expressions.Contains (cleanupExpression)) {
214                                 return;
215                         }
216
217                         epilogue_expressions.Add (cleanupExpression);
218                 }
219
220                 public void AssertEmptyStack ()
221                 {
222 #if STATIC
223                         if (ig.__StackHeight != 0)
224                                 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
225                                         member_context.GetSignatureForError ());
226 #endif
227                 }
228
229                 /// <summary>
230                 ///   This is called immediately before emitting an IL opcode to tell the symbol
231                 ///   writer to which source line this opcode belongs.
232                 /// </summary>
233                 public bool Mark (Location loc)
234                 {
235                         if ((flags & Options.OmitDebugInfo) != 0)
236                                 return false;
237
238                         if (loc.IsNull || methodSymbols == null)
239                                 return false;
240
241                         var sf = loc.SourceFile;
242                         if (sf.IsHiddenLocation (loc))
243                                 return false;
244
245 #if NET_4_0
246                         methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
247 #endif
248                         return true;
249                 }
250
251                 public void DefineLocalVariable (string name, LocalBuilder builder)
252                 {
253                         if ((flags & Options.OmitDebugInfo) != 0)
254                                 return;
255
256                         methodSymbols.AddLocal (builder.LocalIndex, name);
257                 }
258
259                 public void BeginCatchBlock (TypeSpec type)
260                 {
261                         ig.BeginCatchBlock (type.GetMetaInfo ());
262                 }
263
264                 public void BeginExceptionBlock ()
265                 {
266                         ig.BeginExceptionBlock ();
267                 }
268
269                 public void BeginFinallyBlock ()
270                 {
271                         ig.BeginFinallyBlock ();
272                 }
273
274                 public void BeginScope ()
275                 {
276                         if ((flags & Options.OmitDebugInfo) != 0)
277                                 return;
278
279 #if NET_4_0
280                         methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
281 #endif
282                 }
283
284                 public void EndExceptionBlock ()
285                 {
286                         ig.EndExceptionBlock ();
287                 }
288
289                 public void EndScope ()
290                 {
291                         if ((flags & Options.OmitDebugInfo) != 0)
292                                 return;
293
294 #if NET_4_0
295                         methodSymbols.EndBlock (ig.ILOffset);
296 #endif
297                 }
298
299                 //
300                 // Creates a nested container in this context for all dynamic compiler generated stuff
301                 //
302                 internal DynamicSiteClass CreateDynamicSite ()
303                 {
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);
307
308                                 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
309                                 dynamic_site_container.CreateContainer ();
310                                 dynamic_site_container.DefineContainer ();
311                                 dynamic_site_container.Define ();
312
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);
316                         }
317
318                         return dynamic_site_container;
319                 }
320
321                 public Label CreateReturnLabel ()
322                 {
323                         if (!return_label.HasValue)
324                                 return_label = DefineLabel ();
325
326                         return return_label.Value;
327                 }
328
329                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
330                 {
331                         if (IsAnonymousStoreyMutateRequired)
332                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
333
334                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
335                 }
336
337                 public Label DefineLabel ()
338                 {
339                         return ig.DefineLabel ();
340                 }
341
342                 //
343                 // Creates temporary field in current async storey
344                 //
345                 public FieldExpr GetTemporaryField (TypeSpec type)
346                 {
347                         var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
348                         var fexpr = new StackFieldExpr (f);
349                         fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
350                         return fexpr;
351                 }
352
353                 public void MarkLabel (Label label)
354                 {
355                         ig.MarkLabel (label);
356                 }
357
358                 public void Emit (OpCode opcode)
359                 {
360                         ig.Emit (opcode);
361                 }
362
363                 public void Emit (OpCode opcode, LocalBuilder local)
364                 {
365                         ig.Emit (opcode, local);
366                 }
367
368                 public void Emit (OpCode opcode, string arg)
369                 {
370                         ig.Emit (opcode, arg);
371                 }
372
373                 public void Emit (OpCode opcode, double arg)
374                 {
375                         ig.Emit (opcode, arg);
376                 }
377
378                 public void Emit (OpCode opcode, float arg)
379                 {
380                         ig.Emit (opcode, arg);
381                 }
382
383                 public void Emit (OpCode opcode, Label label)
384                 {
385                         ig.Emit (opcode, label);
386                 }
387
388                 public void Emit (OpCode opcode, Label[] labels)
389                 {
390                         ig.Emit (opcode, labels);
391                 }
392
393                 public void Emit (OpCode opcode, TypeSpec type)
394                 {
395                         if (IsAnonymousStoreyMutateRequired)
396                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
397
398                         ig.Emit (opcode, type.GetMetaInfo ());
399                 }
400
401                 public void Emit (OpCode opcode, FieldSpec field)
402                 {
403                         if (IsAnonymousStoreyMutateRequired)
404                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
405
406                         ig.Emit (opcode, field.GetMetaInfo ());
407                 }
408
409                 public void Emit (OpCode opcode, MethodSpec method)
410                 {
411                         if (IsAnonymousStoreyMutateRequired)
412                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
413
414                         if (method.IsConstructor)
415                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
416                         else
417                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
418                 }
419
420                 // TODO: REMOVE breaks mutator
421                 public void Emit (OpCode opcode, MethodInfo method)
422                 {
423                         ig.Emit (opcode, method);
424                 }
425
426                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
427                 {
428                         // TODO MemberCache: This should mutate too
429                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
430                 }
431
432                 public void EmitArrayNew (ArrayContainer ac)
433                 {
434                         if (ac.Rank == 1) {
435                                 var type = IsAnonymousStoreyMutateRequired ?
436                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
437                                         ac.Element;
438
439                                 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
440                         } else {
441                                 if (IsAnonymousStoreyMutateRequired)
442                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
443
444                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
445                         }
446                 }
447
448                 public void EmitArrayAddress (ArrayContainer ac)
449                 {
450                         if (ac.Rank > 1) {
451                                 if (IsAnonymousStoreyMutateRequired)
452                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
453
454                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
455                         } else {
456                                 var type = IsAnonymousStoreyMutateRequired ?
457                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
458                                         ac.Element;
459
460                                 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
461                         }
462                 }
463
464                 //
465                 // Emits the right opcode to load from an array
466                 //
467                 public void EmitArrayLoad (ArrayContainer ac)
468                 {
469                         if (ac.Rank > 1) {
470                                 if (IsAnonymousStoreyMutateRequired)
471                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
472
473                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
474                                 return;
475                         }
476
477
478                         var type = ac.Element;
479                         if (type.Kind == MemberKind.Enum)
480                                 type = EnumSpec.GetUnderlyingType (type);
481
482                         switch (type.BuiltinType) {
483                         case BuiltinTypeSpec.Type.Byte:
484                         case BuiltinTypeSpec.Type.Bool:
485                                 ig.Emit (OpCodes.Ldelem_U1);
486                                 break;
487                         case BuiltinTypeSpec.Type.SByte:
488                                 ig.Emit (OpCodes.Ldelem_I1);
489                                 break;
490                         case BuiltinTypeSpec.Type.Short:
491                                 ig.Emit (OpCodes.Ldelem_I2);
492                                 break;
493                         case BuiltinTypeSpec.Type.UShort:
494                         case BuiltinTypeSpec.Type.Char:
495                                 ig.Emit (OpCodes.Ldelem_U2);
496                                 break;
497                         case BuiltinTypeSpec.Type.Int:
498                                 ig.Emit (OpCodes.Ldelem_I4);
499                                 break;
500                         case BuiltinTypeSpec.Type.UInt:
501                                 ig.Emit (OpCodes.Ldelem_U4);
502                                 break;
503                         case BuiltinTypeSpec.Type.ULong:
504                         case BuiltinTypeSpec.Type.Long:
505                                 ig.Emit (OpCodes.Ldelem_I8);
506                                 break;
507                         case BuiltinTypeSpec.Type.Float:
508                                 ig.Emit (OpCodes.Ldelem_R4);
509                                 break;
510                         case BuiltinTypeSpec.Type.Double:
511                                 ig.Emit (OpCodes.Ldelem_R8);
512                                 break;
513                         case BuiltinTypeSpec.Type.IntPtr:
514                                 ig.Emit (OpCodes.Ldelem_I);
515                                 break;
516                         default:
517                                 switch (type.Kind) {
518                                 case MemberKind.Struct:
519                                         if (IsAnonymousStoreyMutateRequired)
520                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
521
522                                         ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
523                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
524                                         break;
525                                 case MemberKind.TypeParameter:
526                                         if (IsAnonymousStoreyMutateRequired)
527                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
528
529                                         ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
530                                         break;
531                                 case MemberKind.PointerType:
532                                         ig.Emit (OpCodes.Ldelem_I);
533                                         break;
534                                 default:
535                                         ig.Emit (OpCodes.Ldelem_Ref);
536                                         break;
537                                 }
538                                 break;
539                         }
540                 }
541
542                 //
543                 // Emits the right opcode to store to an array
544                 //
545                 public void EmitArrayStore (ArrayContainer ac)
546                 {
547                         if (ac.Rank > 1) {
548                                 if (IsAnonymousStoreyMutateRequired)
549                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
550
551                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
552                                 return;
553                         }
554
555                         var type = ac.Element;
556
557                         if (type.Kind == MemberKind.Enum)
558                                 type = EnumSpec.GetUnderlyingType (type);
559
560                         switch (type.BuiltinType) {
561                         case BuiltinTypeSpec.Type.Byte:
562                         case BuiltinTypeSpec.Type.SByte:
563                         case BuiltinTypeSpec.Type.Bool:
564                                 Emit (OpCodes.Stelem_I1);
565                                 return;
566                         case BuiltinTypeSpec.Type.Short:
567                         case BuiltinTypeSpec.Type.UShort:
568                         case BuiltinTypeSpec.Type.Char:
569                                 Emit (OpCodes.Stelem_I2);
570                                 return;
571                         case BuiltinTypeSpec.Type.Int:
572                         case BuiltinTypeSpec.Type.UInt:
573                                 Emit (OpCodes.Stelem_I4);
574                                 return;
575                         case BuiltinTypeSpec.Type.Long:
576                         case BuiltinTypeSpec.Type.ULong:
577                                 Emit (OpCodes.Stelem_I8);
578                                 return;
579                         case BuiltinTypeSpec.Type.Float:
580                                 Emit (OpCodes.Stelem_R4);
581                                 return;
582                         case BuiltinTypeSpec.Type.Double:
583                                 Emit (OpCodes.Stelem_R8);
584                                 return;
585                         }
586
587                         switch (type.Kind) {
588                         case MemberKind.Struct:
589                                 Emit (OpCodes.Stobj, type);
590                                 break;
591                         case MemberKind.TypeParameter:
592                                 Emit (OpCodes.Stelem, type);
593                                 break;
594                         case MemberKind.PointerType:
595                                 Emit (OpCodes.Stelem_I);
596                                 break;
597                         default:
598                                 Emit (OpCodes.Stelem_Ref);
599                                 break;
600                         }
601                 }
602
603                 public void EmitInt (int i)
604                 {
605                         EmitIntConstant (i);
606                 }
607
608                 void EmitIntConstant (int i)
609                 {
610                         switch (i) {
611                         case -1:
612                                 ig.Emit (OpCodes.Ldc_I4_M1);
613                                 break;
614
615                         case 0:
616                                 ig.Emit (OpCodes.Ldc_I4_0);
617                                 break;
618
619                         case 1:
620                                 ig.Emit (OpCodes.Ldc_I4_1);
621                                 break;
622
623                         case 2:
624                                 ig.Emit (OpCodes.Ldc_I4_2);
625                                 break;
626
627                         case 3:
628                                 ig.Emit (OpCodes.Ldc_I4_3);
629                                 break;
630
631                         case 4:
632                                 ig.Emit (OpCodes.Ldc_I4_4);
633                                 break;
634
635                         case 5:
636                                 ig.Emit (OpCodes.Ldc_I4_5);
637                                 break;
638
639                         case 6:
640                                 ig.Emit (OpCodes.Ldc_I4_6);
641                                 break;
642
643                         case 7:
644                                 ig.Emit (OpCodes.Ldc_I4_7);
645                                 break;
646
647                         case 8:
648                                 ig.Emit (OpCodes.Ldc_I4_8);
649                                 break;
650
651                         default:
652                                 if (i >= -128 && i <= 127) {
653                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
654                                 } else
655                                         ig.Emit (OpCodes.Ldc_I4, i);
656                                 break;
657                         }
658                 }
659
660                 public void EmitLong (long l)
661                 {
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);
668                         } else {
669                                 ig.Emit (OpCodes.Ldc_I8, l);
670                         }
671                 }
672
673                 //
674                 // Load the object from the pointer.  
675                 //
676                 public void EmitLoadFromPtr (TypeSpec type)
677                 {
678                         if (type.Kind == MemberKind.Enum)
679                                 type = EnumSpec.GetUnderlyingType (type);
680
681                         switch (type.BuiltinType) {
682                         case BuiltinTypeSpec.Type.Int:
683                                 ig.Emit (OpCodes.Ldind_I4);
684                                 break;
685                         case BuiltinTypeSpec.Type.UInt:
686                                 ig.Emit (OpCodes.Ldind_U4);
687                                 break;
688                         case BuiltinTypeSpec.Type.Short:
689                                 ig.Emit (OpCodes.Ldind_I2);
690                                 break;
691                         case BuiltinTypeSpec.Type.UShort:
692                         case BuiltinTypeSpec.Type.Char:
693                                 ig.Emit (OpCodes.Ldind_U2);
694                                 break;
695                         case BuiltinTypeSpec.Type.Byte:
696                                 ig.Emit (OpCodes.Ldind_U1);
697                                 break;
698                         case BuiltinTypeSpec.Type.SByte:
699                         case BuiltinTypeSpec.Type.Bool:
700                                 ig.Emit (OpCodes.Ldind_I1);
701                                 break;
702                         case BuiltinTypeSpec.Type.ULong:
703                         case BuiltinTypeSpec.Type.Long:
704                                 ig.Emit (OpCodes.Ldind_I8);
705                                 break;
706                         case BuiltinTypeSpec.Type.Float:
707                                 ig.Emit (OpCodes.Ldind_R4);
708                                 break;
709                         case BuiltinTypeSpec.Type.Double:
710                                 ig.Emit (OpCodes.Ldind_R8);
711                                 break;
712                         case BuiltinTypeSpec.Type.IntPtr:
713                                 ig.Emit (OpCodes.Ldind_I);
714                                 break;
715                         default:
716                                 switch (type.Kind) {
717                                 case MemberKind.Struct:
718                                 case MemberKind.TypeParameter:
719                                         if (IsAnonymousStoreyMutateRequired)
720                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
721
722                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
723                                         break;
724                                 case MemberKind.PointerType:
725                                         ig.Emit (OpCodes.Ldind_I);
726                                         break;
727                                 default:
728                                         ig.Emit (OpCodes.Ldind_Ref);
729                                         break;
730                                 }
731                                 break;
732                         }
733                 }
734
735                 public void EmitNull ()
736                 {
737                         ig.Emit (OpCodes.Ldnull);
738                 }
739
740                 public void EmitArgumentAddress (int pos)
741                 {
742                         if (!IsStatic)
743                                 ++pos;
744
745                         if (pos > byte.MaxValue)
746                                 ig.Emit (OpCodes.Ldarga, pos);
747                         else
748                                 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
749                 }
750
751                 public void EmitArgumentLoad (int pos)
752                 {
753                         if (!IsStatic)
754                                 ++pos;
755
756                         switch (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;
761                         default:
762                                 if (pos > byte.MaxValue)
763                                         ig.Emit (OpCodes.Ldarg, pos);
764                                 else
765                                         ig.Emit (OpCodes.Ldarg_S, (byte) pos);
766                                 break;
767                         }
768                 }
769
770                 public void EmitArgumentStore (int pos)
771                 {
772                         if (!IsStatic)
773                                 ++pos;
774
775                         if (pos > byte.MaxValue)
776                                 ig.Emit (OpCodes.Starg, pos);
777                         else
778                                 ig.Emit (OpCodes.Starg_S, (byte) pos);
779                 }
780
781                 //
782                 // The stack contains the pointer and the value of type `type'
783                 //
784                 public void EmitStoreFromPtr (TypeSpec type)
785                 {
786                         if (type.IsEnum)
787                                 type = EnumSpec.GetUnderlyingType (type);
788
789                         switch (type.BuiltinType) {
790                         case BuiltinTypeSpec.Type.Int:
791                         case BuiltinTypeSpec.Type.UInt:
792                                 ig.Emit (OpCodes.Stind_I4);
793                                 return;
794                         case BuiltinTypeSpec.Type.Long:
795                         case BuiltinTypeSpec.Type.ULong:
796                                 ig.Emit (OpCodes.Stind_I8);
797                                 return;
798                         case BuiltinTypeSpec.Type.Char:
799                         case BuiltinTypeSpec.Type.Short:
800                         case BuiltinTypeSpec.Type.UShort:
801                                 ig.Emit (OpCodes.Stind_I2);
802                                 return;
803                         case BuiltinTypeSpec.Type.Float:
804                                 ig.Emit (OpCodes.Stind_R4);
805                                 return;
806                         case BuiltinTypeSpec.Type.Double:
807                                 ig.Emit (OpCodes.Stind_R8);
808                                 return;
809                         case BuiltinTypeSpec.Type.Byte:
810                         case BuiltinTypeSpec.Type.SByte:
811                         case BuiltinTypeSpec.Type.Bool:
812                                 ig.Emit (OpCodes.Stind_I1);
813                                 return;
814                         case BuiltinTypeSpec.Type.IntPtr:
815                                 ig.Emit (OpCodes.Stind_I);
816                                 return;
817                         }
818
819                         switch (type.Kind) {
820                         case MemberKind.Struct:
821                         case MemberKind.TypeParameter:
822                                 if (IsAnonymousStoreyMutateRequired)
823                                         type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
824
825                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
826                                 break;
827                         default:
828                                 ig.Emit (OpCodes.Stind_Ref);
829                                 break;
830                         }
831                 }
832
833                 public void EmitThis ()
834                 {
835                         ig.Emit (OpCodes.Ldarg_0);
836                 }
837
838                 public void EmitEpilogue ()
839                 {
840                         if (epilogue_expressions == null)
841                                 return;
842
843                         foreach (var e in epilogue_expressions)
844                                 e.EmitCleanup (this);
845
846                         epilogue_expressions = null;
847                 }
848
849                 /// <summary>
850                 ///   Returns a temporary storage for a variable of type t as 
851                 ///   a local variable in the current body.
852                 /// </summary>
853                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
854                 {
855                         if (temporary_storage != null) {
856                                 object o;
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 ();
861                                         } else {
862                                                 temporary_storage.Remove (t);
863                                         }
864                                 }
865                                 if (o != null)
866                                         return (LocalBuilder) o;
867                         }
868                         return DeclareLocal (t, false);
869                 }
870
871                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
872                 {
873                         if (temporary_storage == null) {
874                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
875                                 temporary_storage.Add (t, b);
876                                 return;
877                         }
878                         object o;
879                         
880                         if (!temporary_storage.TryGetValue (t, out o)) {
881                                 temporary_storage.Add (t, b);
882                                 return;
883                         }
884                         var s = o as Stack<LocalBuilder>;
885                         if (s == null) {
886                                 s = new Stack<LocalBuilder> ();
887                                 s.Push ((LocalBuilder)o);
888                                 temporary_storage [t] = s;
889                         }
890                         s.Push (b);
891                 }
892
893                 /// <summary>
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.
898                 ///
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.
904                 /// </summary>
905                 public LocalBuilder TemporaryReturn ()
906                 {
907                         if (return_value == null){
908                                 return_value = DeclareLocal (return_type, false);
909                         }
910
911                         return return_value;
912                 }
913         }
914
915         struct CallEmitter
916         {
917                 public Expression InstanceExpression;
918
919                 //
920                 // When set leaves an extra copy of all arguments on the stack
921                 //
922                 public bool DuplicateArguments;
923
924                 //
925                 // Does not emit InstanceExpression load when InstanceExpressionOnStack
926                 // is set. Used by compound assignments.
927                 //
928                 public bool InstanceExpressionOnStack;
929
930                 //
931                 // Any of arguments contains await expression
932                 //
933                 public bool HasAwaitArguments;
934
935                 //
936                 // When dealing with await arguments the original arguments are converted
937                 // into a new set with hoisted stack results
938                 //
939                 public Arguments EmittedArguments;
940
941                 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
942                 {
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))
945                                 return;
946
947                         EmitPredefined (ec, method, Arguments, loc);
948                 }
949
950                 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, Location? loc = null)
951                 {
952                         Expression instance_copy = null;
953
954                         if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
955                                 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
956                                 if (HasAwaitArguments && InstanceExpressionOnStack) {
957                                         throw new NotSupportedException ();
958                                 }
959                         }
960
961                         OpCode call_op;
962                         LocalTemporary lt = null;
963
964                         if (method.IsStatic) {
965                                 call_op = OpCodes.Call;
966                         } else {
967                                 if (IsVirtualCallRequired (InstanceExpression, method)) {
968                                         call_op = OpCodes.Callvirt;
969                                 } else {
970                                         call_op = OpCodes.Call;
971                                 }
972
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);
979
980                                         if (DuplicateArguments) {
981                                                 ec.Emit (OpCodes.Dup);
982                                                 if (Arguments != null && Arguments.Count != 0) {
983                                                         lt = new LocalTemporary (instance_on_stack_type);
984                                                         lt.Store (ec);
985                                                         instance_copy = lt;
986                                                 }
987                                         }
988                                 }
989                         }
990
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);
996
997                                                 if (lt != null)
998                                                         lt.Release (ec);
999                                         }
1000
1001                                         EmittedArguments.Emit (ec);
1002                                 }
1003                         }
1004
1005                         if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
1006                                 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
1007                         }
1008
1009                         if (loc != null) {
1010                                 //
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
1013                                 //
1014                                 // TODO: The list is probably not comprehensive, need to do more testing
1015                                 //
1016                                 if (InstanceExpression is PropertyExpr || InstanceExpression is Invocation || InstanceExpression is IndexerExpr ||
1017                                         InstanceExpression is New || InstanceExpression is DelegateInvocation)
1018                                         ec.Mark (loc.Value);
1019                         }
1020
1021                         //
1022                         // Set instance expression to actual result expression. When it contains await it can be
1023                         // picked up by caller
1024                         //
1025                         InstanceExpression = instance_copy;
1026
1027                         if (method.Parameters.HasArglist) {
1028                                 var varargs_types = GetVarargsTypes (method, Arguments);
1029                                 ec.Emit (call_op, method, varargs_types);
1030                                 return;
1031                         }
1032
1033                         //
1034                         // If you have:
1035                         // this.DoFoo ();
1036                         // and DoFoo is not virtual, you can omit the callvirt,
1037                         // because you don't need the null checking behavior.
1038                         //
1039                         ec.Emit (call_op, method);
1040                 }
1041
1042                 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
1043                 {
1044                         var instance_type = instance.Type;
1045
1046                         //
1047                         // Push the instance expression
1048                         //
1049                         if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1050                                 instance_type.IsGenericParameter || declaringType.IsNullableType) {
1051                                 //
1052                                 // If the expression implements IMemoryLocation, then
1053                                 // we can optimize and use AddressOf on the
1054                                 // return.
1055                                 //
1056                                 // If not we have to use some temporary storage for
1057                                 // it.
1058                                 var iml = instance as IMemoryLocation;
1059                                 if (iml != null) {
1060                                         iml.AddressOf (ec, AddressOp.Load);
1061                                 } else {
1062                                         LocalTemporary temp = new LocalTemporary (instance_type);
1063                                         instance.Emit (ec);
1064                                         temp.Store (ec);
1065                                         temp.AddressOf (ec, AddressOp.Load);
1066                                 }
1067
1068                                 return ReferenceContainer.MakeType (ec.Module, instance_type);
1069                         }
1070
1071                         if (instance_type.IsEnum || instance_type.IsStruct) {
1072                                 instance.Emit (ec);
1073                                 ec.Emit (OpCodes.Box, instance_type);
1074                                 return ec.BuiltinTypes.Object;
1075                         }
1076
1077                         instance.Emit (ec);
1078                         return instance_type;
1079                 }
1080
1081                 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1082                 {
1083                         AParametersCollection pd = method.Parameters;
1084
1085                         Argument a = arguments[pd.Count - 1];
1086                         Arglist list = (Arglist) a.Expr;
1087
1088                         return list.ArgumentTypes;
1089                 }
1090
1091                 //
1092                 // Used to decide whether call or callvirt is needed
1093                 //
1094                 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1095                 {
1096                         //
1097                         // There are 2 scenarious where we emit callvirt
1098                         //
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
1102                         //
1103                         var decl_type = method.DeclaringType;
1104                         if (decl_type.IsStruct || decl_type.IsEnum)
1105                                 return false;
1106
1107                         if (instance is BaseThis)
1108                                 return false;
1109
1110                         //
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
1113                         //
1114                         if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation) &&
1115                                 !instance.Type.IsGenericParameter)
1116                                 return false;
1117
1118                         return true;
1119                 }
1120         }
1121 }