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