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