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