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