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