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