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