Merge branch 'xml-fixes' of https://github.com/myeisha/mono into myeisha-xml-fixes
[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 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.InteropServices;
17 using System.Security.Cryptography;
18
19 namespace Mono.CSharp {
20
21         /// <summary>
22         ///    Code generator class.
23         /// </summary>
24         public class CodeGen {
25                 static AppDomain current_domain;
26
27                 // Breaks dynamic and repl
28                 public static AssemblyClass Assembly;
29
30                 static CodeGen ()
31                 {
32                         Reset ();
33                 }
34
35                 public static void Reset ()
36                 {
37                         Assembly = new AssemblyClass ();
38                 }
39
40                 public static string Basename (string name)
41                 {
42                         int pos = name.LastIndexOf ('/');
43
44                         if (pos != -1)
45                                 return name.Substring (pos + 1);
46
47                         pos = name.LastIndexOf ('\\');
48                         if (pos != -1)
49                                 return name.Substring (pos + 1);
50
51                         return name;
52                 }
53
54                 public static string Dirname (string name)
55                 {
56                         int pos = name.LastIndexOf ('/');
57
58                         if (pos != -1)
59                                 return name.Substring (0, pos);
60
61                         pos = name.LastIndexOf ('\\');
62                         if (pos != -1)
63                                 return name.Substring (0, pos);
64
65                         return ".";
66                 }
67
68                 static public string FileName;
69                                 
70                 //
71                 // Initializes the code generator variables for interactive use (repl)
72                 //
73                 static public void InitDynamic (CompilerContext ctx, string name)
74                 {
75                         current_domain = AppDomain.CurrentDomain;
76                         AssemblyName an = Assembly.GetAssemblyName (name, name);
77                         
78                         Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
79                         RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
80                         RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
81                         Assembly.Name = Assembly.Builder.GetName ();
82                 }
83
84                 //
85                 // Initializes the code generator variables
86                 //
87                 static public bool Init (string name, string output, bool want_debugging_support, CompilerContext ctx)
88                 {
89                         FileName = output;
90                         AssemblyName an = Assembly.GetAssemblyName (name, output);
91                         if (an == null)
92                                 return false;
93
94                         if (an.KeyPair != null) {
95                                 // If we are going to strong name our assembly make
96                                 // sure all its refs are strong named
97                                 foreach (Assembly a in ctx.GlobalRootNamespace.Assemblies) {
98                                         AssemblyName ref_name = a.GetName ();
99                                         byte [] b = ref_name.GetPublicKeyToken ();
100                                         if (b == null || b.Length == 0) {
101                                                 ctx.Report.Error (1577, "Assembly generation failed " +
102                                                                 "-- Referenced assembly '" +
103                                                                 ref_name.Name +
104                                                                 "' does not have a strong name.");
105                                                 //Environment.Exit (1);
106                                         }
107                                 }
108                         }
109                         
110                         current_domain = AppDomain.CurrentDomain;
111
112                         try {
113                                 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
114                                         AssemblyBuilderAccess.RunAndSave, Dirname (name));
115                         }
116                         catch (ArgumentException) {
117                                 // specified key may not be exportable outside it's container
118                                 if (RootContext.StrongNameKeyContainer != null) {
119                                         ctx.Report.Error (1548, "Could not access the key inside the container `" +
120                                                 RootContext.StrongNameKeyContainer + "'.");
121                                         Environment.Exit (1);
122                                 }
123                                 throw;
124                         }
125                         catch (CryptographicException) {
126                                 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
127                                         ctx.Report.Error (1548, "Could not use the specified key to strongname the assembly.");
128                                         Environment.Exit (1);
129                                 }
130                                 return false;
131                         }
132
133                         // Get the complete AssemblyName from the builder
134                         // (We need to get the public key and token)
135                         Assembly.Name = Assembly.Builder.GetName ();
136
137                         //
138                         // Pass a path-less name to DefineDynamicModule.  Wonder how
139                         // this copes with output in different directories then.
140                         // FIXME: figure out how this copes with --output /tmp/blah
141                         //
142                         // If the third argument is true, the ModuleBuilder will dynamically
143                         // load the default symbol writer.
144                         //
145                         try {
146                                 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
147                                         Basename (name), Basename (output), want_debugging_support);
148
149 #if !MS_COMPATIBLE
150                                 // TODO: We should use SymbolWriter from DefineDynamicModule
151                                 if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
152                                         ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
153                                                 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
154                                         return false;
155                                 }
156 #endif
157                         } catch (ExecutionEngineException e) {
158                                 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
159                                         e.Message);
160                                 return false;
161                         }
162
163                         return true;
164                 }
165
166                 public static void Save (string name, Report Report)
167                 {
168                         PortableExecutableKinds pekind;
169                         ImageFileMachine machine;
170
171                         switch (RootContext.Platform) {
172                         case Platform.X86:
173                                 pekind = PortableExecutableKinds.Required32Bit | PortableExecutableKinds.ILOnly;
174                                 machine = ImageFileMachine.I386;
175                                 break;
176                         case Platform.X64:
177                                 pekind = PortableExecutableKinds.ILOnly;
178                                 machine = ImageFileMachine.AMD64;
179                                 break;
180                         case Platform.IA64:
181                                 pekind = PortableExecutableKinds.ILOnly;
182                                 machine = ImageFileMachine.IA64;
183                                 break;
184                         case Platform.AnyCPU:
185                         default:
186                                 pekind = PortableExecutableKinds.ILOnly;
187                                 machine = ImageFileMachine.I386;
188                                 break;
189                         }
190                         try {
191                                 Assembly.Builder.Save (Basename (name), pekind, machine);
192                         }
193                         catch (COMException) {
194                                 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
195                                         throw;
196
197                                 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
198                                 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
199                                         RootContext.StrongNameKeyFile +
200                                         "', Use MCS with the Mono runtime or CSC to compile this assembly.");
201                         }
202                         catch (System.IO.IOException io) {
203                                 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
204                                 return;
205                         }
206                         catch (System.UnauthorizedAccessException ua) {
207                                 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
208                                 return;
209                         }
210                         catch (System.NotImplementedException nie) {
211                                 Report.RuntimeMissingSupport (Location.Null, nie.Message);
212                                 return;
213                         }
214                 }
215         }
216
217         /// <summary>
218         ///   An Emit Context is created for each body of code (from methods,
219         ///   properties bodies, indexer bodies or constructor bodies)
220         /// </summary>
221         public class EmitContext : BuilderContext
222         {
223                 // TODO: Has to be private
224                 public ILGenerator ig;
225
226                 /// <summary>
227                 ///   The value that is allowed to be returned or NULL if there is no
228                 ///   return type.
229                 /// </summary>
230                 TypeSpec return_type;
231
232                 /// <summary>
233                 ///   Keeps track of the Type to LocalBuilder temporary storage created
234                 ///   to store structures (used to compute the address of the structure
235                 ///   value on structure method invocations)
236                 /// </summary>
237                 Dictionary<TypeSpec, object> temporary_storage;
238
239                 /// <summary>
240                 ///   The location where we store the return value.
241                 /// </summary>
242                 public LocalBuilder return_value;
243
244                 /// <summary>
245                 ///   The location where return has to jump to return the
246                 ///   value
247                 /// </summary>
248                 public Label ReturnLabel;
249
250                 /// <summary>
251                 ///   If we already defined the ReturnLabel
252                 /// </summary>
253                 public bool HasReturnLabel;
254
255                 /// <summary>
256                 ///   Current loop begin and end labels.
257                 /// </summary>
258                 public Label LoopBegin, LoopEnd;
259
260                 /// <summary>
261                 ///   Default target in a switch statement.   Only valid if
262                 ///   InSwitch is true
263                 /// </summary>
264                 public Label DefaultTarget;
265
266                 /// <summary>
267                 ///   If this is non-null, points to the current switch statement
268                 /// </summary>
269                 public Switch Switch;
270
271                 /// <summary>
272                 ///  Whether we are inside an anonymous method.
273                 /// </summary>
274                 public AnonymousExpression CurrentAnonymousMethod;
275                 
276                 public readonly IMemberContext MemberContext;
277
278                 DynamicSiteClass dynamic_site_container;
279
280                 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
281                 {
282                         this.MemberContext = rc;
283                         this.ig = ig;
284
285                         this.return_type = return_type;
286                 }
287
288                 #region Properties
289
290                 public TypeSpec CurrentType {
291                         get { return MemberContext.CurrentType; }
292                 }
293
294                 public TypeParameter[] CurrentTypeParameters {
295                         get { return MemberContext.CurrentTypeParameters; }
296                 }
297
298                 public MemberCore CurrentTypeDefinition {
299                         get { return MemberContext.CurrentMemberDefinition; }
300                 }
301
302                 public bool IsStatic {
303                         get { return MemberContext.IsStatic; }
304                 }
305
306                 bool IsAnonymousStoreyMutateRequired {
307                         get {
308                                 return CurrentAnonymousMethod != null &&
309                                         CurrentAnonymousMethod.Storey != null &&
310                                         CurrentAnonymousMethod.Storey.Mutator != null;
311                         }
312                 }
313
314                 // Has to be used for emitter errors only
315                 public Report Report {
316                         get { return MemberContext.Compiler.Report; }
317                 }
318
319                 public TypeSpec ReturnType {
320                         get {
321                                 return return_type;
322                         }
323                 }
324 #endregion
325
326                 /// <summary>
327                 ///   This is called immediately before emitting an IL opcode to tell the symbol
328                 ///   writer to which source line this opcode belongs.
329                 /// </summary>
330                 public void Mark (Location loc)
331                 {
332                         if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
333                                 return;
334
335                         SymbolWriter.MarkSequencePoint (ig, loc);
336                 }
337
338                 public void DefineLocalVariable (string name, LocalBuilder builder)
339                 {
340                         SymbolWriter.DefineLocalVariable (name, builder);
341                 }
342
343                 public void BeginCatchBlock (TypeSpec type)
344                 {
345                         ig.BeginCatchBlock (type.GetMetaInfo ());
346                 }
347
348                 public void BeginExceptionBlock ()
349                 {
350                         ig.BeginExceptionBlock ();
351                 }
352
353                 public void BeginFinallyBlock ()
354                 {
355                         ig.BeginFinallyBlock ();
356                 }
357
358                 public void BeginScope ()
359                 {
360                         ig.BeginScope();
361                         SymbolWriter.OpenScope(ig);
362                 }
363
364                 public void EndExceptionBlock ()
365                 {
366                         ig.EndExceptionBlock ();
367                 }
368
369                 public void EndScope ()
370                 {
371                         ig.EndScope();
372                         SymbolWriter.CloseScope(ig);
373                 }
374
375                 //
376                 // Creates a nested container in this context for all dynamic compiler generated stuff
377                 //
378                 public DynamicSiteClass CreateDynamicSite ()
379                 {
380                         if (dynamic_site_container == null) {
381                                 var mc = MemberContext.CurrentMemberDefinition as MemberBase;
382                                 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
383
384                                 RootContext.ToplevelTypes.AddCompilerGeneratedClass (dynamic_site_container);
385                                 dynamic_site_container.CreateType ();
386                                 dynamic_site_container.DefineType ();
387                                 dynamic_site_container.ResolveTypeParameters ();
388                                 dynamic_site_container.Define ();
389                         }
390
391                         return dynamic_site_container;
392                 }
393
394                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
395                 {
396                         if (IsAnonymousStoreyMutateRequired)
397                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
398
399                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
400                 }
401
402                 public Label DefineLabel ()
403                 {
404                         return ig.DefineLabel ();
405                 }
406
407                 public void MarkLabel (Label label)
408                 {
409                         ig.MarkLabel (label);
410                 }
411
412                 public void Emit (OpCode opcode)
413                 {
414                         ig.Emit (opcode);
415                 }
416
417                 public void Emit (OpCode opcode, LocalBuilder local)
418                 {
419                         ig.Emit (opcode, local);
420                 }
421
422                 public void Emit (OpCode opcode, string arg)
423                 {
424                         ig.Emit (opcode, arg);
425                 }
426
427                 public void Emit (OpCode opcode, double arg)
428                 {
429                         ig.Emit (opcode, arg);
430                 }
431
432                 public void Emit (OpCode opcode, float arg)
433                 {
434                         ig.Emit (opcode, arg);
435                 }
436
437                 public void Emit (OpCode opcode, int arg)
438                 {
439                         ig.Emit (opcode, arg);
440                 }
441
442                 public void Emit (OpCode opcode, byte arg)
443                 {
444                         ig.Emit (opcode, arg);
445                 }
446
447                 public void Emit (OpCode opcode, Label label)
448                 {
449                         ig.Emit (opcode, label);
450                 }
451
452                 public void Emit (OpCode opcode, Label[] labels)
453                 {
454                         ig.Emit (opcode, labels);
455                 }
456
457                 public void Emit (OpCode opcode, TypeSpec type)
458                 {
459                         if (IsAnonymousStoreyMutateRequired)
460                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
461
462                         ig.Emit (opcode, type.GetMetaInfo ());
463                 }
464
465                 public void Emit (OpCode opcode, FieldSpec field)
466                 {
467                         if (IsAnonymousStoreyMutateRequired)
468                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
469
470                         ig.Emit (opcode, field.GetMetaInfo ());
471                 }
472
473                 public void Emit (OpCode opcode, MethodSpec method)
474                 {
475                         if (IsAnonymousStoreyMutateRequired)
476                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
477
478                         if (method.IsConstructor)
479                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
480                         else
481                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
482                 }
483
484                 // TODO: REMOVE breaks mutator
485                 public void Emit (OpCode opcode, MethodInfo method)
486                 {
487                         ig.Emit (opcode, method);
488                 }
489
490                 // TODO: REMOVE breaks mutator
491                 public void Emit (OpCode opcode, FieldBuilder field)
492                 {
493                         ig.Emit (opcode, field);
494                 }
495
496                 public void Emit (OpCode opcode, MethodSpec method, Type[] vargs)
497                 {
498                         // TODO MemberCache: This should mutate too
499                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
500                 }
501
502                 public void EmitArrayNew (ArrayContainer ac)
503                 {
504                         if (ac.Rank == 1) {
505                                 Emit (OpCodes.Newarr, ac.Element);
506                         } else {
507                                 if (IsAnonymousStoreyMutateRequired)
508                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
509
510                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
511                         }
512                 }
513
514                 public void EmitArrayAddress (ArrayContainer ac)
515                 {
516                         if (ac.Element.IsGenericParameter)
517                                 ig.Emit (OpCodes.Readonly);
518
519                         if (ac.Rank > 1) {
520                                 if (IsAnonymousStoreyMutateRequired)
521                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
522
523                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
524                         } else {
525                                 Emit (OpCodes.Ldelema, ac.Element);
526                         }
527                 }
528
529                 //
530                 // Emits the right opcode to load from an array
531                 //
532                 public void EmitArrayLoad (ArrayContainer ac)
533                 {
534                         if (ac.Rank > 1) {
535                                 if (IsAnonymousStoreyMutateRequired)
536                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
537
538                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
539                                 return;
540                         }
541
542                         var type = ac.Element;
543                         if (TypeManager.IsEnumType (type))
544                                 type = EnumSpec.GetUnderlyingType (type);
545
546                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
547                                 Emit (OpCodes.Ldelem_U1);
548                         else if (type == TypeManager.sbyte_type)
549                                 Emit (OpCodes.Ldelem_I1);
550                         else if (type == TypeManager.short_type)
551                                 Emit (OpCodes.Ldelem_I2);
552                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
553                                 Emit (OpCodes.Ldelem_U2);
554                         else if (type == TypeManager.int32_type)
555                                 Emit (OpCodes.Ldelem_I4);
556                         else if (type == TypeManager.uint32_type)
557                                 Emit (OpCodes.Ldelem_U4);
558                         else if (type == TypeManager.uint64_type)
559                                 Emit (OpCodes.Ldelem_I8);
560                         else if (type == TypeManager.int64_type)
561                                 Emit (OpCodes.Ldelem_I8);
562                         else if (type == TypeManager.float_type)
563                                 Emit (OpCodes.Ldelem_R4);
564                         else if (type == TypeManager.double_type)
565                                 Emit (OpCodes.Ldelem_R8);
566                         else if (type == TypeManager.intptr_type)
567                                 Emit (OpCodes.Ldelem_I);
568                         else if (TypeManager.IsStruct (type)) {
569                                 Emit (OpCodes.Ldelema, type);
570                                 Emit (OpCodes.Ldobj, type);
571                         } else if (type.IsGenericParameter) {
572                                 Emit (OpCodes.Ldelem, type);
573                         } else if (type.IsPointer)
574                                 Emit (OpCodes.Ldelem_I);
575                         else
576                                 Emit (OpCodes.Ldelem_Ref);
577                 }
578
579                 //
580                 // Emits the right opcode to store to an array
581                 //
582                 public void EmitArrayStore (ArrayContainer ac)
583                 {
584                         if (ac.Rank > 1) {
585                                 if (IsAnonymousStoreyMutateRequired)
586                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
587
588                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
589                                 return;
590                         }
591
592                         var type = ac.Element;
593
594                         if (type.IsEnum)
595                                 type = EnumSpec.GetUnderlyingType (type);
596
597                         if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.bool_type)
598                                 Emit (OpCodes.Stelem_I1);
599                         else if (type == TypeManager.short_type || type == TypeManager.ushort_type || type == TypeManager.char_type)
600                                 Emit (OpCodes.Stelem_I2);
601                         else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
602                                 Emit (OpCodes.Stelem_I4);
603                         else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
604                                 Emit (OpCodes.Stelem_I8);
605                         else if (type == TypeManager.float_type)
606                                 Emit (OpCodes.Stelem_R4);
607                         else if (type == TypeManager.double_type)
608                                 Emit (OpCodes.Stelem_R8);
609                         else if (type == TypeManager.intptr_type)
610                                 Emit (OpCodes.Stobj, type);
611                         else if (TypeManager.IsStruct (type))
612                                 Emit (OpCodes.Stobj, type);
613                         else if (type.IsGenericParameter)
614                                 Emit (OpCodes.Stelem, type);
615                         else if (type.IsPointer)
616                                 Emit (OpCodes.Stelem_I);
617                         else
618                                 Emit (OpCodes.Stelem_Ref);
619                 }
620
621                 public void EmitInt (int i)
622                 {
623                         switch (i) {
624                         case -1:
625                                 ig.Emit (OpCodes.Ldc_I4_M1);
626                                 break;
627
628                         case 0:
629                                 ig.Emit (OpCodes.Ldc_I4_0);
630                                 break;
631
632                         case 1:
633                                 ig.Emit (OpCodes.Ldc_I4_1);
634                                 break;
635
636                         case 2:
637                                 ig.Emit (OpCodes.Ldc_I4_2);
638                                 break;
639
640                         case 3:
641                                 ig.Emit (OpCodes.Ldc_I4_3);
642                                 break;
643
644                         case 4:
645                                 ig.Emit (OpCodes.Ldc_I4_4);
646                                 break;
647
648                         case 5:
649                                 ig.Emit (OpCodes.Ldc_I4_5);
650                                 break;
651
652                         case 6:
653                                 ig.Emit (OpCodes.Ldc_I4_6);
654                                 break;
655
656                         case 7:
657                                 ig.Emit (OpCodes.Ldc_I4_7);
658                                 break;
659
660                         case 8:
661                                 ig.Emit (OpCodes.Ldc_I4_8);
662                                 break;
663
664                         default:
665                                 if (i >= -128 && i <= 127) {
666                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
667                                 } else
668                                         ig.Emit (OpCodes.Ldc_I4, i);
669                                 break;
670                         }
671                 }
672
673                 public void EmitLong (long l)
674                 {
675                         if (l >= int.MinValue && l <= int.MaxValue) {
676                                 EmitInt (unchecked ((int) l));
677                                 ig.Emit (OpCodes.Conv_I8);
678                                 return;
679                         }
680
681                         if (l >= 0 && l <= uint.MaxValue) {
682                                 EmitInt (unchecked ((int) l));
683                                 ig.Emit (OpCodes.Conv_U8);
684                                 return;
685                         }
686
687                         ig.Emit (OpCodes.Ldc_I8, l);
688                 }
689
690                 //
691                 // Load the object from the pointer.  
692                 //
693                 public void EmitLoadFromPtr (TypeSpec t)
694                 {
695                         if (t == TypeManager.int32_type)
696                                 ig.Emit (OpCodes.Ldind_I4);
697                         else if (t == TypeManager.uint32_type)
698                                 ig.Emit (OpCodes.Ldind_U4);
699                         else if (t == TypeManager.short_type)
700                                 ig.Emit (OpCodes.Ldind_I2);
701                         else if (t == TypeManager.ushort_type)
702                                 ig.Emit (OpCodes.Ldind_U2);
703                         else if (t == TypeManager.char_type)
704                                 ig.Emit (OpCodes.Ldind_U2);
705                         else if (t == TypeManager.byte_type)
706                                 ig.Emit (OpCodes.Ldind_U1);
707                         else if (t == TypeManager.sbyte_type)
708                                 ig.Emit (OpCodes.Ldind_I1);
709                         else if (t == TypeManager.uint64_type)
710                                 ig.Emit (OpCodes.Ldind_I8);
711                         else if (t == TypeManager.int64_type)
712                                 ig.Emit (OpCodes.Ldind_I8);
713                         else if (t == TypeManager.float_type)
714                                 ig.Emit (OpCodes.Ldind_R4);
715                         else if (t == TypeManager.double_type)
716                                 ig.Emit (OpCodes.Ldind_R8);
717                         else if (t == TypeManager.bool_type)
718                                 ig.Emit (OpCodes.Ldind_I1);
719                         else if (t == TypeManager.intptr_type)
720                                 ig.Emit (OpCodes.Ldind_I);
721                         else if (t.IsEnum) {
722                                 if (t == TypeManager.enum_type)
723                                         ig.Emit (OpCodes.Ldind_Ref);
724                                 else
725                                         EmitLoadFromPtr (EnumSpec.GetUnderlyingType (t));
726                         } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
727                                 Emit (OpCodes.Ldobj, t);
728                         else if (t.IsPointer)
729                                 ig.Emit (OpCodes.Ldind_I);
730                         else
731                                 ig.Emit (OpCodes.Ldind_Ref);
732                 }
733
734                 //
735                 // The stack contains the pointer and the value of type `type'
736                 //
737                 public void EmitStoreFromPtr (TypeSpec type)
738                 {
739                         if (type.IsEnum)
740                                 type = EnumSpec.GetUnderlyingType (type);
741
742                         if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
743                                 ig.Emit (OpCodes.Stind_I4);
744                         else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
745                                 ig.Emit (OpCodes.Stind_I8);
746                         else if (type == TypeManager.char_type || type == TypeManager.short_type ||
747                                  type == TypeManager.ushort_type)
748                                 ig.Emit (OpCodes.Stind_I2);
749                         else if (type == TypeManager.float_type)
750                                 ig.Emit (OpCodes.Stind_R4);
751                         else if (type == TypeManager.double_type)
752                                 ig.Emit (OpCodes.Stind_R8);
753                         else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
754                                  type == TypeManager.bool_type)
755                                 ig.Emit (OpCodes.Stind_I1);
756                         else if (type == TypeManager.intptr_type)
757                                 ig.Emit (OpCodes.Stind_I);
758                         else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
759                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
760                         else
761                                 ig.Emit (OpCodes.Stind_Ref);
762                 }
763
764                 /// <summary>
765                 ///   Returns a temporary storage for a variable of type t as 
766                 ///   a local variable in the current body.
767                 /// </summary>
768                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
769                 {
770                         if (temporary_storage != null) {
771                                 object o;
772                                 if (temporary_storage.TryGetValue (t, out o)) {
773                                         if (o is Stack<LocalBuilder>) {
774                                                 var s = (Stack<LocalBuilder>) o;
775                                                 o = s.Count == 0 ? null : s.Pop ();
776                                         } else {
777                                                 temporary_storage.Remove (t);
778                                         }
779                                 }
780                                 if (o != null)
781                                         return (LocalBuilder) o;
782                         }
783                         return DeclareLocal (t, false);
784                 }
785
786                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
787                 {
788                         if (temporary_storage == null) {
789                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
790                                 temporary_storage.Add (t, b);
791                                 return;
792                         }
793                         object o;
794                         
795                         if (!temporary_storage.TryGetValue (t, out o)) {
796                                 temporary_storage.Add (t, b);
797                                 return;
798                         }
799                         var s = o as Stack<LocalBuilder>;
800                         if (s == null) {
801                                 s = new Stack<LocalBuilder> ();
802                                 s.Push ((LocalBuilder)o);
803                                 temporary_storage [t] = s;
804                         }
805                         s.Push (b);
806                 }
807
808                 /// <summary>
809                 ///   ReturnValue creates on demand the LocalBuilder for the
810                 ///   return value from the function.  By default this is not
811                 ///   used.  This is only required when returns are found inside
812                 ///   Try or Catch statements.
813                 ///
814                 ///   This method is typically invoked from the Emit phase, so
815                 ///   we allow the creation of a return label if it was not
816                 ///   requested during the resolution phase.   Could be cleaned
817                 ///   up, but it would replicate a lot of logic in the Emit phase
818                 ///   of the code that uses it.
819                 /// </summary>
820                 public LocalBuilder TemporaryReturn ()
821                 {
822                         if (return_value == null){
823                                 return_value = DeclareLocal (return_type, false);
824                                 if (!HasReturnLabel){
825                                         ReturnLabel = DefineLabel ();
826                                         HasReturnLabel = true;
827                                 }
828                         }
829
830                         return return_value;
831                 }
832         }
833 }