Merge pull request #1074 from esdrubal/bug18421
[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                 public LocalVariable AsyncThrowVariable { get; set; }
208
209                 #endregion
210
211                 public void AddStatementEpilog (IExpressionCleanup cleanupExpression)
212                 {
213                         if (epilogue_expressions == null) {
214                                 epilogue_expressions = new List<IExpressionCleanup> ();
215                         } else if (epilogue_expressions.Contains (cleanupExpression)) {
216                                 return;
217                         }
218
219                         epilogue_expressions.Add (cleanupExpression);
220                 }
221
222                 public void AssertEmptyStack ()
223                 {
224 #if STATIC
225                         if (ig.__StackHeight != 0)
226                                 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
227                                         member_context.GetSignatureForError ());
228 #endif
229                 }
230
231                 /// <summary>
232                 ///   This is called immediately before emitting an IL opcode to tell the symbol
233                 ///   writer to which source line this opcode belongs.
234                 /// </summary>
235                 public bool Mark (Location loc)
236                 {
237                         if ((flags & Options.OmitDebugInfo) != 0)
238                                 return false;
239
240                         if (loc.IsNull || methodSymbols == null)
241                                 return false;
242
243                         var sf = loc.SourceFile;
244                         if (sf.IsHiddenLocation (loc))
245                                 return false;
246
247 #if NET_4_0
248                         methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
249 #endif
250                         return true;
251                 }
252
253                 public void MarkCallEntry (Location loc)
254                 {
255                         if (!EmitAccurateDebugInfo)
256                                 return;
257
258                         //
259                         // TODO: This should emit different kind of sequence point to make
260                         // step-over work for statement over multiple lines
261                         //
262                         // Debugging experience for Foo (A () + B ()) where A and B are
263                         // on separate lines is not great
264                         //
265                         Mark (loc);
266                 }
267
268                 public void DefineLocalVariable (string name, LocalBuilder builder)
269                 {
270                         if ((flags & Options.OmitDebugInfo) != 0)
271                                 return;
272
273                         methodSymbols.AddLocal (builder.LocalIndex, name);
274                 }
275
276                 public void BeginCatchBlock (TypeSpec type)
277                 {
278                         if (IsAnonymousStoreyMutateRequired)
279                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
280
281                         ig.BeginCatchBlock (type.GetMetaInfo ());
282                 }
283
284                 public void BeginFilterHandler ()
285                 {
286                         ig.BeginCatchBlock (null);
287                 }
288
289                 public void BeginExceptionBlock ()
290                 {
291                         ig.BeginExceptionBlock ();
292                 }
293
294                 public void BeginExceptionFilterBlock ()
295                 {
296                         ig.BeginExceptFilterBlock ();
297                 }
298
299                 public void BeginFinallyBlock ()
300                 {
301                         ig.BeginFinallyBlock ();
302                 }
303
304                 public void BeginScope ()
305                 {
306                         if ((flags & Options.OmitDebugInfo) != 0)
307                                 return;
308
309 #if NET_4_0
310                         methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
311 #endif
312                 }
313
314                 public void BeginCompilerScope ()
315                 {
316                         if ((flags & Options.OmitDebugInfo) != 0)
317                                 return;
318
319 #if NET_4_0
320                         methodSymbols.StartBlock (CodeBlockEntry.Type.CompilerGenerated, ig.ILOffset);
321 #endif
322                 }
323
324                 public void EndExceptionBlock ()
325                 {
326                         ig.EndExceptionBlock ();
327                 }
328
329                 public void EndScope ()
330                 {
331                         if ((flags & Options.OmitDebugInfo) != 0)
332                                 return;
333
334 #if NET_4_0
335                         methodSymbols.EndBlock (ig.ILOffset);
336 #endif
337                 }
338
339                 //
340                 // Creates a nested container in this context for all dynamic compiler generated stuff
341                 //
342                 internal DynamicSiteClass CreateDynamicSite ()
343                 {
344                         if (dynamic_site_container == null) {
345                                 var mc = member_context.CurrentMemberDefinition as MemberBase;
346                                 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
347
348                                 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
349                                 dynamic_site_container.CreateContainer ();
350                                 dynamic_site_container.DefineContainer ();
351                                 dynamic_site_container.Define ();
352
353                                 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
354                                 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
355                                 CurrentType.MemberCache.AddMember (inflated);
356                         }
357
358                         return dynamic_site_container;
359                 }
360
361                 public Label CreateReturnLabel ()
362                 {
363                         if (!return_label.HasValue)
364                                 return_label = DefineLabel ();
365
366                         return return_label.Value;
367                 }
368
369                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
370                 {
371                         if (IsAnonymousStoreyMutateRequired)
372                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
373
374                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
375                 }
376
377                 public Label DefineLabel ()
378                 {
379                         return ig.DefineLabel ();
380                 }
381
382                 //
383                 // Creates temporary field in current async storey
384                 //
385                 public StackFieldExpr GetTemporaryField (TypeSpec type)
386                 {
387                         var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
388                         var fexpr = new StackFieldExpr (f);
389                         fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
390                         return fexpr;
391                 }
392
393                 public void MarkLabel (Label label)
394                 {
395                         ig.MarkLabel (label);
396                 }
397
398                 public void Emit (OpCode opcode)
399                 {
400                         ig.Emit (opcode);
401                 }
402
403                 public void Emit (OpCode opcode, LocalBuilder local)
404                 {
405                         ig.Emit (opcode, local);
406                 }
407
408                 public void Emit (OpCode opcode, string arg)
409                 {
410                         ig.Emit (opcode, arg);
411                 }
412
413                 public void Emit (OpCode opcode, double arg)
414                 {
415                         ig.Emit (opcode, arg);
416                 }
417
418                 public void Emit (OpCode opcode, float arg)
419                 {
420                         ig.Emit (opcode, arg);
421                 }
422
423                 public void Emit (OpCode opcode, Label label)
424                 {
425                         ig.Emit (opcode, label);
426                 }
427
428                 public void Emit (OpCode opcode, Label[] labels)
429                 {
430                         ig.Emit (opcode, labels);
431                 }
432
433                 public void Emit (OpCode opcode, TypeSpec type)
434                 {
435                         if (IsAnonymousStoreyMutateRequired)
436                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
437
438                         ig.Emit (opcode, type.GetMetaInfo ());
439                 }
440
441                 public void Emit (OpCode opcode, FieldSpec field)
442                 {
443                         if (IsAnonymousStoreyMutateRequired)
444                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
445
446                         ig.Emit (opcode, field.GetMetaInfo ());
447                 }
448
449                 public void Emit (OpCode opcode, MethodSpec method)
450                 {
451                         if (IsAnonymousStoreyMutateRequired)
452                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
453
454                         if (method.IsConstructor)
455                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
456                         else
457                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
458                 }
459
460                 // TODO: REMOVE breaks mutator
461                 public void Emit (OpCode opcode, MethodInfo method)
462                 {
463                         ig.Emit (opcode, method);
464                 }
465
466                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
467                 {
468                         // TODO MemberCache: This should mutate too
469                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
470                 }
471
472                 public void EmitArrayNew (ArrayContainer ac)
473                 {
474                         if (ac.Rank == 1) {
475                                 var type = IsAnonymousStoreyMutateRequired ?
476                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
477                                         ac.Element;
478
479                                 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
480                         } else {
481                                 if (IsAnonymousStoreyMutateRequired)
482                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
483
484                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
485                         }
486                 }
487
488                 public void EmitArrayAddress (ArrayContainer ac)
489                 {
490                         if (ac.Rank > 1) {
491                                 if (IsAnonymousStoreyMutateRequired)
492                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
493
494                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
495                         } else {
496                                 var type = IsAnonymousStoreyMutateRequired ?
497                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
498                                         ac.Element;
499
500                                 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
501                         }
502                 }
503
504                 //
505                 // Emits the right opcode to load from an array
506                 //
507                 public void EmitArrayLoad (ArrayContainer ac)
508                 {
509                         if (ac.Rank > 1) {
510                                 if (IsAnonymousStoreyMutateRequired)
511                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
512
513                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
514                                 return;
515                         }
516
517
518                         var type = ac.Element;
519                         if (type.Kind == MemberKind.Enum)
520                                 type = EnumSpec.GetUnderlyingType (type);
521
522                         switch (type.BuiltinType) {
523                         case BuiltinTypeSpec.Type.Byte:
524                         case BuiltinTypeSpec.Type.Bool:
525                                 ig.Emit (OpCodes.Ldelem_U1);
526                                 break;
527                         case BuiltinTypeSpec.Type.SByte:
528                                 ig.Emit (OpCodes.Ldelem_I1);
529                                 break;
530                         case BuiltinTypeSpec.Type.Short:
531                                 ig.Emit (OpCodes.Ldelem_I2);
532                                 break;
533                         case BuiltinTypeSpec.Type.UShort:
534                         case BuiltinTypeSpec.Type.Char:
535                                 ig.Emit (OpCodes.Ldelem_U2);
536                                 break;
537                         case BuiltinTypeSpec.Type.Int:
538                                 ig.Emit (OpCodes.Ldelem_I4);
539                                 break;
540                         case BuiltinTypeSpec.Type.UInt:
541                                 ig.Emit (OpCodes.Ldelem_U4);
542                                 break;
543                         case BuiltinTypeSpec.Type.ULong:
544                         case BuiltinTypeSpec.Type.Long:
545                                 ig.Emit (OpCodes.Ldelem_I8);
546                                 break;
547                         case BuiltinTypeSpec.Type.Float:
548                                 ig.Emit (OpCodes.Ldelem_R4);
549                                 break;
550                         case BuiltinTypeSpec.Type.Double:
551                                 ig.Emit (OpCodes.Ldelem_R8);
552                                 break;
553                         case BuiltinTypeSpec.Type.IntPtr:
554                                 ig.Emit (OpCodes.Ldelem_I);
555                                 break;
556                         default:
557                                 switch (type.Kind) {
558                                 case MemberKind.Struct:
559                                         if (IsAnonymousStoreyMutateRequired)
560                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
561
562                                         ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
563                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
564                                         break;
565                                 case MemberKind.TypeParameter:
566                                         if (IsAnonymousStoreyMutateRequired)
567                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
568
569                                         ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
570                                         break;
571                                 case MemberKind.PointerType:
572                                         ig.Emit (OpCodes.Ldelem_I);
573                                         break;
574                                 default:
575                                         ig.Emit (OpCodes.Ldelem_Ref);
576                                         break;
577                                 }
578                                 break;
579                         }
580                 }
581
582                 //
583                 // Emits the right opcode to store to an array
584                 //
585                 public void EmitArrayStore (ArrayContainer ac)
586                 {
587                         if (ac.Rank > 1) {
588                                 if (IsAnonymousStoreyMutateRequired)
589                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
590
591                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
592                                 return;
593                         }
594
595                         var type = ac.Element;
596
597                         if (type.Kind == MemberKind.Enum)
598                                 type = EnumSpec.GetUnderlyingType (type);
599
600                         switch (type.BuiltinType) {
601                         case BuiltinTypeSpec.Type.Byte:
602                         case BuiltinTypeSpec.Type.SByte:
603                         case BuiltinTypeSpec.Type.Bool:
604                                 Emit (OpCodes.Stelem_I1);
605                                 return;
606                         case BuiltinTypeSpec.Type.Short:
607                         case BuiltinTypeSpec.Type.UShort:
608                         case BuiltinTypeSpec.Type.Char:
609                                 Emit (OpCodes.Stelem_I2);
610                                 return;
611                         case BuiltinTypeSpec.Type.Int:
612                         case BuiltinTypeSpec.Type.UInt:
613                                 Emit (OpCodes.Stelem_I4);
614                                 return;
615                         case BuiltinTypeSpec.Type.Long:
616                         case BuiltinTypeSpec.Type.ULong:
617                                 Emit (OpCodes.Stelem_I8);
618                                 return;
619                         case BuiltinTypeSpec.Type.Float:
620                                 Emit (OpCodes.Stelem_R4);
621                                 return;
622                         case BuiltinTypeSpec.Type.Double:
623                                 Emit (OpCodes.Stelem_R8);
624                                 return;
625                         }
626
627                         switch (type.Kind) {
628                         case MemberKind.Struct:
629                                 Emit (OpCodes.Stobj, type);
630                                 break;
631                         case MemberKind.TypeParameter:
632                                 Emit (OpCodes.Stelem, type);
633                                 break;
634                         case MemberKind.PointerType:
635                                 Emit (OpCodes.Stelem_I);
636                                 break;
637                         default:
638                                 Emit (OpCodes.Stelem_Ref);
639                                 break;
640                         }
641                 }
642
643                 public void EmitInt (int i)
644                 {
645                         EmitIntConstant (i);
646                 }
647
648                 void EmitIntConstant (int i)
649                 {
650                         switch (i) {
651                         case -1:
652                                 ig.Emit (OpCodes.Ldc_I4_M1);
653                                 break;
654
655                         case 0:
656                                 ig.Emit (OpCodes.Ldc_I4_0);
657                                 break;
658
659                         case 1:
660                                 ig.Emit (OpCodes.Ldc_I4_1);
661                                 break;
662
663                         case 2:
664                                 ig.Emit (OpCodes.Ldc_I4_2);
665                                 break;
666
667                         case 3:
668                                 ig.Emit (OpCodes.Ldc_I4_3);
669                                 break;
670
671                         case 4:
672                                 ig.Emit (OpCodes.Ldc_I4_4);
673                                 break;
674
675                         case 5:
676                                 ig.Emit (OpCodes.Ldc_I4_5);
677                                 break;
678
679                         case 6:
680                                 ig.Emit (OpCodes.Ldc_I4_6);
681                                 break;
682
683                         case 7:
684                                 ig.Emit (OpCodes.Ldc_I4_7);
685                                 break;
686
687                         case 8:
688                                 ig.Emit (OpCodes.Ldc_I4_8);
689                                 break;
690
691                         default:
692                                 if (i >= -128 && i <= 127) {
693                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
694                                 } else
695                                         ig.Emit (OpCodes.Ldc_I4, i);
696                                 break;
697                         }
698                 }
699
700                 public void EmitLong (long l)
701                 {
702                         if (l >= int.MinValue && l <= int.MaxValue) {
703                                 EmitIntConstant (unchecked ((int) l));
704                                 ig.Emit (OpCodes.Conv_I8);
705                         } else if (l >= 0 && l <= uint.MaxValue) {
706                                 EmitIntConstant (unchecked ((int) l));
707                                 ig.Emit (OpCodes.Conv_U8);
708                         } else {
709                                 ig.Emit (OpCodes.Ldc_I8, l);
710                         }
711                 }
712
713                 //
714                 // Load the object from the pointer.  
715                 //
716                 public void EmitLoadFromPtr (TypeSpec type)
717                 {
718                         if (type.Kind == MemberKind.Enum)
719                                 type = EnumSpec.GetUnderlyingType (type);
720
721                         switch (type.BuiltinType) {
722                         case BuiltinTypeSpec.Type.Int:
723                                 ig.Emit (OpCodes.Ldind_I4);
724                                 break;
725                         case BuiltinTypeSpec.Type.UInt:
726                                 ig.Emit (OpCodes.Ldind_U4);
727                                 break;
728                         case BuiltinTypeSpec.Type.Short:
729                                 ig.Emit (OpCodes.Ldind_I2);
730                                 break;
731                         case BuiltinTypeSpec.Type.UShort:
732                         case BuiltinTypeSpec.Type.Char:
733                                 ig.Emit (OpCodes.Ldind_U2);
734                                 break;
735                         case BuiltinTypeSpec.Type.Byte:
736                                 ig.Emit (OpCodes.Ldind_U1);
737                                 break;
738                         case BuiltinTypeSpec.Type.SByte:
739                         case BuiltinTypeSpec.Type.Bool:
740                                 ig.Emit (OpCodes.Ldind_I1);
741                                 break;
742                         case BuiltinTypeSpec.Type.ULong:
743                         case BuiltinTypeSpec.Type.Long:
744                                 ig.Emit (OpCodes.Ldind_I8);
745                                 break;
746                         case BuiltinTypeSpec.Type.Float:
747                                 ig.Emit (OpCodes.Ldind_R4);
748                                 break;
749                         case BuiltinTypeSpec.Type.Double:
750                                 ig.Emit (OpCodes.Ldind_R8);
751                                 break;
752                         case BuiltinTypeSpec.Type.IntPtr:
753                                 ig.Emit (OpCodes.Ldind_I);
754                                 break;
755                         default:
756                                 switch (type.Kind) {
757                                 case MemberKind.Struct:
758                                 case MemberKind.TypeParameter:
759                                         if (IsAnonymousStoreyMutateRequired)
760                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
761
762                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
763                                         break;
764                                 case MemberKind.PointerType:
765                                         ig.Emit (OpCodes.Ldind_I);
766                                         break;
767                                 default:
768                                         ig.Emit (OpCodes.Ldind_Ref);
769                                         break;
770                                 }
771                                 break;
772                         }
773                 }
774
775                 public void EmitNull ()
776                 {
777                         ig.Emit (OpCodes.Ldnull);
778                 }
779
780                 public void EmitArgumentAddress (int pos)
781                 {
782                         if (!IsStatic)
783                                 ++pos;
784
785                         if (pos > byte.MaxValue)
786                                 ig.Emit (OpCodes.Ldarga, pos);
787                         else
788                                 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
789                 }
790
791                 public void EmitArgumentLoad (int pos)
792                 {
793                         if (!IsStatic)
794                                 ++pos;
795
796                         switch (pos) {
797                         case 0: ig.Emit (OpCodes.Ldarg_0); break;
798                         case 1: ig.Emit (OpCodes.Ldarg_1); break;
799                         case 2: ig.Emit (OpCodes.Ldarg_2); break;
800                         case 3: ig.Emit (OpCodes.Ldarg_3); break;
801                         default:
802                                 if (pos > byte.MaxValue)
803                                         ig.Emit (OpCodes.Ldarg, pos);
804                                 else
805                                         ig.Emit (OpCodes.Ldarg_S, (byte) pos);
806                                 break;
807                         }
808                 }
809
810                 public void EmitArgumentStore (int pos)
811                 {
812                         if (!IsStatic)
813                                 ++pos;
814
815                         if (pos > byte.MaxValue)
816                                 ig.Emit (OpCodes.Starg, pos);
817                         else
818                                 ig.Emit (OpCodes.Starg_S, (byte) pos);
819                 }
820
821                 //
822                 // The stack contains the pointer and the value of type `type'
823                 //
824                 public void EmitStoreFromPtr (TypeSpec type)
825                 {
826                         if (type.IsEnum)
827                                 type = EnumSpec.GetUnderlyingType (type);
828
829                         switch (type.BuiltinType) {
830                         case BuiltinTypeSpec.Type.Int:
831                         case BuiltinTypeSpec.Type.UInt:
832                                 ig.Emit (OpCodes.Stind_I4);
833                                 return;
834                         case BuiltinTypeSpec.Type.Long:
835                         case BuiltinTypeSpec.Type.ULong:
836                                 ig.Emit (OpCodes.Stind_I8);
837                                 return;
838                         case BuiltinTypeSpec.Type.Char:
839                         case BuiltinTypeSpec.Type.Short:
840                         case BuiltinTypeSpec.Type.UShort:
841                                 ig.Emit (OpCodes.Stind_I2);
842                                 return;
843                         case BuiltinTypeSpec.Type.Float:
844                                 ig.Emit (OpCodes.Stind_R4);
845                                 return;
846                         case BuiltinTypeSpec.Type.Double:
847                                 ig.Emit (OpCodes.Stind_R8);
848                                 return;
849                         case BuiltinTypeSpec.Type.Byte:
850                         case BuiltinTypeSpec.Type.SByte:
851                         case BuiltinTypeSpec.Type.Bool:
852                                 ig.Emit (OpCodes.Stind_I1);
853                                 return;
854                         case BuiltinTypeSpec.Type.IntPtr:
855                                 ig.Emit (OpCodes.Stind_I);
856                                 return;
857                         }
858
859                         switch (type.Kind) {
860                         case MemberKind.Struct:
861                         case MemberKind.TypeParameter:
862                                 if (IsAnonymousStoreyMutateRequired)
863                                         type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
864
865                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
866                                 break;
867                         default:
868                                 ig.Emit (OpCodes.Stind_Ref);
869                                 break;
870                         }
871                 }
872
873                 public void EmitThis ()
874                 {
875                         ig.Emit (OpCodes.Ldarg_0);
876                 }
877
878                 public void EmitEpilogue ()
879                 {
880                         if (epilogue_expressions == null)
881                                 return;
882
883                         foreach (var e in epilogue_expressions)
884                                 e.EmitCleanup (this);
885
886                         epilogue_expressions = null;
887                 }
888
889                 /// <summary>
890                 ///   Returns a temporary storage for a variable of type t as 
891                 ///   a local variable in the current body.
892                 /// </summary>
893                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
894                 {
895                         if (temporary_storage != null) {
896                                 object o;
897                                 if (temporary_storage.TryGetValue (t, out o)) {
898                                         if (o is Stack<LocalBuilder>) {
899                                                 var s = (Stack<LocalBuilder>) o;
900                                                 o = s.Count == 0 ? null : s.Pop ();
901                                         } else {
902                                                 temporary_storage.Remove (t);
903                                         }
904                                 }
905                                 if (o != null)
906                                         return (LocalBuilder) o;
907                         }
908                         return DeclareLocal (t, false);
909                 }
910
911                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
912                 {
913                         if (temporary_storage == null) {
914                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
915                                 temporary_storage.Add (t, b);
916                                 return;
917                         }
918                         object o;
919                         
920                         if (!temporary_storage.TryGetValue (t, out o)) {
921                                 temporary_storage.Add (t, b);
922                                 return;
923                         }
924                         var s = o as Stack<LocalBuilder>;
925                         if (s == null) {
926                                 s = new Stack<LocalBuilder> ();
927                                 s.Push ((LocalBuilder)o);
928                                 temporary_storage [t] = s;
929                         }
930                         s.Push (b);
931                 }
932
933                 /// <summary>
934                 ///   ReturnValue creates on demand the LocalBuilder for the
935                 ///   return value from the function.  By default this is not
936                 ///   used.  This is only required when returns are found inside
937                 ///   Try or Catch statements.
938                 ///
939                 ///   This method is typically invoked from the Emit phase, so
940                 ///   we allow the creation of a return label if it was not
941                 ///   requested during the resolution phase.   Could be cleaned
942                 ///   up, but it would replicate a lot of logic in the Emit phase
943                 ///   of the code that uses it.
944                 /// </summary>
945                 public LocalBuilder TemporaryReturn ()
946                 {
947                         if (return_value == null){
948                                 return_value = DeclareLocal (return_type, false);
949                         }
950
951                         return return_value;
952                 }
953         }
954
955         struct CallEmitter
956         {
957                 public Expression InstanceExpression;
958
959                 //
960                 // When set leaves an extra copy of all arguments on the stack
961                 //
962                 public bool DuplicateArguments;
963
964                 //
965                 // Does not emit InstanceExpression load when InstanceExpressionOnStack
966                 // is set. Used by compound assignments.
967                 //
968                 public bool InstanceExpressionOnStack;
969
970                 //
971                 // Any of arguments contains await expression
972                 //
973                 public bool HasAwaitArguments;
974
975                 //
976                 // When dealing with await arguments the original arguments are converted
977                 // into a new set with hoisted stack results
978                 //
979                 public Arguments EmittedArguments;
980
981                 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
982                 {
983                         EmitPredefined (ec, method, Arguments, loc);
984                 }
985
986                 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, Location? loc = null)
987                 {
988                         Expression instance_copy = null;
989
990                         if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
991                                 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
992                                 if (HasAwaitArguments && InstanceExpressionOnStack) {
993                                         throw new NotSupportedException ();
994                                 }
995                         }
996
997                         OpCode call_op;
998                         LocalTemporary lt = null;
999
1000                         if (method.IsStatic) {
1001                                 call_op = OpCodes.Call;
1002                         } else {
1003                                 if (IsVirtualCallRequired (InstanceExpression, method)) {
1004                                         call_op = OpCodes.Callvirt;
1005                                 } else {
1006                                         call_op = OpCodes.Call;
1007                                 }
1008
1009                                 if (HasAwaitArguments) {
1010                                         instance_copy = InstanceExpression.EmitToField (ec);
1011                                         if (Arguments == null)
1012                                                 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
1013                                 } else if (!InstanceExpressionOnStack) {
1014                                         var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
1015
1016                                         if (DuplicateArguments) {
1017                                                 ec.Emit (OpCodes.Dup);
1018                                                 if (Arguments != null && Arguments.Count != 0) {
1019                                                         lt = new LocalTemporary (instance_on_stack_type);
1020                                                         lt.Store (ec);
1021                                                         instance_copy = lt;
1022                                                 }
1023                                         }
1024                                 }
1025                         }
1026
1027                         if (Arguments != null && !InstanceExpressionOnStack) {
1028                                 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
1029                                 if (EmittedArguments != null) {
1030                                         if (instance_copy != null) {
1031                                                 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
1032
1033                                                 if (lt != null)
1034                                                         lt.Release (ec);
1035                                         }
1036
1037                                         EmittedArguments.Emit (ec);
1038                                 }
1039                         }
1040
1041                         if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) {
1042                                 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
1043                         }
1044
1045                         if (loc != null) {
1046                                 //
1047                                 // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
1048                                 // break at right place when LHS expression can be stepped-into
1049                                 //
1050                                 ec.MarkCallEntry (loc.Value);
1051                         }
1052
1053                         //
1054                         // Set instance expression to actual result expression. When it contains await it can be
1055                         // picked up by caller
1056                         //
1057                         InstanceExpression = instance_copy;
1058
1059                         if (method.Parameters.HasArglist) {
1060                                 var varargs_types = GetVarargsTypes (method, Arguments);
1061                                 ec.Emit (call_op, method, varargs_types);
1062                                 return;
1063                         }
1064
1065                         //
1066                         // If you have:
1067                         // this.DoFoo ();
1068                         // and DoFoo is not virtual, you can omit the callvirt,
1069                         // because you don't need the null checking behavior.
1070                         //
1071                         ec.Emit (call_op, method);
1072                 }
1073
1074                 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
1075                 {
1076                         var instance_type = instance.Type;
1077
1078                         //
1079                         // Push the instance expression
1080                         //
1081                         if ((instance_type.IsStructOrEnum && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1082                                 instance_type.IsGenericParameter || declaringType.IsNullableType) {
1083                                 //
1084                                 // If the expression implements IMemoryLocation, then
1085                                 // we can optimize and use AddressOf on the
1086                                 // return.
1087                                 //
1088                                 // If not we have to use some temporary storage for
1089                                 // it.
1090                                 var iml = instance as IMemoryLocation;
1091                                 if (iml != null) {
1092                                         iml.AddressOf (ec, AddressOp.Load);
1093                                 } else {
1094                                         LocalTemporary temp = new LocalTemporary (instance_type);
1095                                         instance.Emit (ec);
1096                                         temp.Store (ec);
1097                                         temp.AddressOf (ec, AddressOp.Load);
1098                                 }
1099
1100                                 return ReferenceContainer.MakeType (ec.Module, instance_type);
1101                         }
1102
1103                         if (instance_type.IsStructOrEnum) {
1104                                 instance.Emit (ec);
1105                                 ec.Emit (OpCodes.Box, instance_type);
1106                                 return ec.BuiltinTypes.Object;
1107                         }
1108
1109                         instance.Emit (ec);
1110                         return instance_type;
1111                 }
1112
1113                 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1114                 {
1115                         AParametersCollection pd = method.Parameters;
1116
1117                         Argument a = arguments[pd.Count - 1];
1118                         Arglist list = (Arglist) a.Expr;
1119
1120                         return list.ArgumentTypes;
1121                 }
1122
1123                 //
1124                 // Used to decide whether call or callvirt is needed
1125                 //
1126                 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1127                 {
1128                         //
1129                         // There are 2 scenarious where we emit callvirt
1130                         //
1131                         // Case 1: A method is virtual and it's not used to call base
1132                         // Case 2: A method instance expression can be null. In this casen callvirt ensures
1133                         // correct NRE exception when the method is called
1134                         //
1135                         var decl_type = method.DeclaringType;
1136                         if (decl_type.IsStruct || decl_type.IsEnum)
1137                                 return false;
1138
1139                         if (instance is BaseThis)
1140                                 return false;
1141
1142                         //
1143                         // It's non-virtual and will never be null and it can be determined
1144                         // whether it's known value or reference type by verifier
1145                         //
1146                         if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation) &&
1147                                 !instance.Type.IsGenericParameter)
1148                                 return false;
1149
1150                         return true;
1151                 }
1152         }
1153 }