4fd8ec82ad8e71b18d5c60b41bf18dec78d9dd83
[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                 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
91                 {
92                         this.member_context = rc;
93                         this.ig = ig;
94
95                         this.return_type = return_type;
96
97 #if STATIC
98                         ig.__CleverExceptionBlockAssistance ();
99 #endif
100                 }
101
102                 #region Properties
103
104                 public BuildinTypes BuildinTypes {
105                         get {
106                                 return MemberContext.Module.Compiler.BuildinTypes;
107                         }
108                 }
109
110                 public TypeSpec CurrentType {
111                         get { return member_context.CurrentType; }
112                 }
113
114                 public TypeParameter[] CurrentTypeParameters {
115                         get { return member_context.CurrentTypeParameters; }
116                 }
117
118                 public MemberCore CurrentTypeDefinition {
119                         get { return member_context.CurrentMemberDefinition; }
120                 }
121
122                 public bool IsStatic {
123                         get { return member_context.IsStatic; }
124                 }
125
126                 bool IsAnonymousStoreyMutateRequired {
127                         get {
128                                 return CurrentAnonymousMethod != null &&
129                                         CurrentAnonymousMethod.Storey != null &&
130                                         CurrentAnonymousMethod.Storey.Mutator != null;
131                         }
132                 }
133
134                 public IMemberContext MemberContext {
135                         get {
136                                 return member_context;
137                         }
138                 }
139
140                 public ModuleContainer Module {
141                         get {
142                                 return member_context.Module;
143                         }
144                 }
145
146                 // Has to be used for specific emitter errors only any
147                 // possible resolver errors have to be reported during Resolve
148                 public Report Report {
149                         get {
150                                 return member_context.Module.Compiler.Report;
151                         }
152                 }
153
154                 public TypeSpec ReturnType {
155                         get {
156                                 return return_type;
157                         }
158                 }
159                 #endregion
160
161                 /// <summary>
162                 ///   This is called immediately before emitting an IL opcode to tell the symbol
163                 ///   writer to which source line this opcode belongs.
164                 /// </summary>
165                 public void Mark (Location loc)
166                 {
167                         if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
168                                 return;
169
170                         SymbolWriter.MarkSequencePoint (ig, loc);
171                 }
172
173                 public void DefineLocalVariable (string name, LocalBuilder builder)
174                 {
175                         SymbolWriter.DefineLocalVariable (name, builder);
176                 }
177
178                 public void BeginCatchBlock (TypeSpec type)
179                 {
180                         ig.BeginCatchBlock (type.GetMetaInfo ());
181                 }
182
183                 public void BeginExceptionBlock ()
184                 {
185                         ig.BeginExceptionBlock ();
186                 }
187
188                 public void BeginFinallyBlock ()
189                 {
190                         ig.BeginFinallyBlock ();
191                 }
192
193                 public void BeginScope ()
194                 {
195                         SymbolWriter.OpenScope(ig);
196                 }
197
198                 public void EndExceptionBlock ()
199                 {
200                         ig.EndExceptionBlock ();
201                 }
202
203                 public void EndScope ()
204                 {
205                         SymbolWriter.CloseScope(ig);
206                 }
207
208                 //
209                 // Creates a nested container in this context for all dynamic compiler generated stuff
210                 //
211                 public DynamicSiteClass CreateDynamicSite ()
212                 {
213                         if (dynamic_site_container == null) {
214                                 var mc = member_context.CurrentMemberDefinition as MemberBase;
215                                 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
216
217                                 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
218                                 dynamic_site_container.CreateType ();
219                                 dynamic_site_container.DefineType ();
220                                 dynamic_site_container.ResolveTypeParameters ();
221                                 dynamic_site_container.Define ();
222                         }
223
224                         return dynamic_site_container;
225                 }
226
227                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
228                 {
229                         if (IsAnonymousStoreyMutateRequired)
230                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
231
232                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
233                 }
234
235                 public Label DefineLabel ()
236                 {
237                         return ig.DefineLabel ();
238                 }
239
240                 public void MarkLabel (Label label)
241                 {
242                         ig.MarkLabel (label);
243                 }
244
245                 public void Emit (OpCode opcode)
246                 {
247                         ig.Emit (opcode);
248                 }
249
250                 public void Emit (OpCode opcode, LocalBuilder local)
251                 {
252                         ig.Emit (opcode, local);
253                 }
254
255                 public void Emit (OpCode opcode, string arg)
256                 {
257                         ig.Emit (opcode, arg);
258                 }
259
260                 public void Emit (OpCode opcode, double arg)
261                 {
262                         ig.Emit (opcode, arg);
263                 }
264
265                 public void Emit (OpCode opcode, float arg)
266                 {
267                         ig.Emit (opcode, arg);
268                 }
269
270                 public void Emit (OpCode opcode, int arg)
271                 {
272                         ig.Emit (opcode, arg);
273                 }
274
275                 public void Emit (OpCode opcode, byte arg)
276                 {
277                         ig.Emit (opcode, arg);
278                 }
279
280                 public void Emit (OpCode opcode, Label label)
281                 {
282                         ig.Emit (opcode, label);
283                 }
284
285                 public void Emit (OpCode opcode, Label[] labels)
286                 {
287                         ig.Emit (opcode, labels);
288                 }
289
290                 public void Emit (OpCode opcode, TypeSpec type)
291                 {
292                         if (IsAnonymousStoreyMutateRequired)
293                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
294
295                         ig.Emit (opcode, type.GetMetaInfo ());
296                 }
297
298                 public void Emit (OpCode opcode, FieldSpec field)
299                 {
300                         if (IsAnonymousStoreyMutateRequired)
301                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
302
303                         ig.Emit (opcode, field.GetMetaInfo ());
304                 }
305
306                 public void Emit (OpCode opcode, MethodSpec method)
307                 {
308                         if (IsAnonymousStoreyMutateRequired)
309                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
310
311                         if (method.IsConstructor)
312                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
313                         else
314                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
315                 }
316
317                 // TODO: REMOVE breaks mutator
318                 public void Emit (OpCode opcode, MethodInfo method)
319                 {
320                         ig.Emit (opcode, method);
321                 }
322
323                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
324                 {
325                         // TODO MemberCache: This should mutate too
326                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
327                 }
328
329                 public void EmitArrayNew (ArrayContainer ac)
330                 {
331                         if (ac.Rank == 1) {
332                                 Emit (OpCodes.Newarr, ac.Element);
333                         } else {
334                                 if (IsAnonymousStoreyMutateRequired)
335                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
336
337                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
338                         }
339                 }
340
341                 public void EmitArrayAddress (ArrayContainer ac)
342                 {
343                         if (ac.Element.IsGenericParameter)
344                                 ig.Emit (OpCodes.Readonly);
345
346                         if (ac.Rank > 1) {
347                                 if (IsAnonymousStoreyMutateRequired)
348                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
349
350                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
351                         } else {
352                                 Emit (OpCodes.Ldelema, ac.Element);
353                         }
354                 }
355
356                 //
357                 // Emits the right opcode to load from an array
358                 //
359                 public void EmitArrayLoad (ArrayContainer ac)
360                 {
361                         if (ac.Rank > 1) {
362                                 if (IsAnonymousStoreyMutateRequired)
363                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
364
365                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
366                                 return;
367                         }
368
369                         var type = ac.Element;
370                         if (type.Kind == MemberKind.Enum)
371                                 type = EnumSpec.GetUnderlyingType (type);
372
373                         switch (type.BuildinType) {
374                         case BuildinTypeSpec.Type.Byte:
375                         case BuildinTypeSpec.Type.Bool:
376                                 Emit (OpCodes.Ldelem_U1);
377                                 return;
378                         case BuildinTypeSpec.Type.SByte:
379                                 Emit (OpCodes.Ldelem_I1);
380                                 return;
381                         case BuildinTypeSpec.Type.Short:
382                                 Emit (OpCodes.Ldelem_I2);
383                                 return;
384                         case BuildinTypeSpec.Type.UShort:
385                         case BuildinTypeSpec.Type.Char:
386                                 Emit (OpCodes.Ldelem_U2);
387                                 return;
388                         case BuildinTypeSpec.Type.Int:
389                                 Emit (OpCodes.Ldelem_I4);
390                                 return;
391                         case BuildinTypeSpec.Type.UInt:
392                                 Emit (OpCodes.Ldelem_U4);
393                                 return;
394                         case BuildinTypeSpec.Type.ULong:
395                         case BuildinTypeSpec.Type.Long:
396                                 Emit (OpCodes.Ldelem_I8);
397                                 return;
398                         case BuildinTypeSpec.Type.Float:
399                                 Emit (OpCodes.Ldelem_R4);
400                                 return;
401                         case BuildinTypeSpec.Type.Double:
402                                 Emit (OpCodes.Ldelem_R8);
403                                 return;
404                         case BuildinTypeSpec.Type.IntPtr:
405                                 Emit (OpCodes.Ldelem_I);
406                                 return;
407                         }
408
409                         switch (type.Kind) {
410                         case MemberKind.Struct:
411                                 Emit (OpCodes.Ldelema, type);
412                                 Emit (OpCodes.Ldobj, type);
413                                 break;
414                         case MemberKind.TypeParameter:
415                                 Emit (OpCodes.Ldelem, type);
416                                 break;
417                         case MemberKind.PointerType:
418                                 Emit (OpCodes.Ldelem_I);
419                                 break;
420                         default:
421                                 Emit (OpCodes.Ldelem_Ref);
422                                 break;
423                         }
424                 }
425
426                 //
427                 // Emits the right opcode to store to an array
428                 //
429                 public void EmitArrayStore (ArrayContainer ac)
430                 {
431                         if (ac.Rank > 1) {
432                                 if (IsAnonymousStoreyMutateRequired)
433                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
434
435                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
436                                 return;
437                         }
438
439                         var type = ac.Element;
440
441                         if (type.Kind == MemberKind.Enum)
442                                 type = EnumSpec.GetUnderlyingType (type);
443
444                         switch (type.BuildinType) {
445                         case BuildinTypeSpec.Type.Byte:
446                         case BuildinTypeSpec.Type.SByte:
447                         case BuildinTypeSpec.Type.Bool:
448                                 Emit (OpCodes.Stelem_I1);
449                                 return;
450                         case BuildinTypeSpec.Type.Short:
451                         case BuildinTypeSpec.Type.UShort:
452                         case BuildinTypeSpec.Type.Char:
453                                 Emit (OpCodes.Stelem_I2);
454                                 return;
455                         case BuildinTypeSpec.Type.Int:
456                         case BuildinTypeSpec.Type.UInt:
457                                 Emit (OpCodes.Stelem_I4);
458                                 return;
459                         case BuildinTypeSpec.Type.Long:
460                         case BuildinTypeSpec.Type.ULong:
461                                 Emit (OpCodes.Stelem_I8);
462                                 return;
463                         case BuildinTypeSpec.Type.Float:
464                                 Emit (OpCodes.Stelem_R4);
465                                 return;
466                         case BuildinTypeSpec.Type.Double:
467                                 Emit (OpCodes.Stelem_R8);
468                                 return;
469                         }
470
471                         switch (type.Kind) {
472                         case MemberKind.Struct:
473                                 Emit (OpCodes.Stobj, type);
474                                 break;
475                         case MemberKind.TypeParameter:
476                                 Emit (OpCodes.Stelem, type);
477                                 break;
478                         case MemberKind.PointerType:
479                                 Emit (OpCodes.Stelem_I);
480                                 break;
481                         default:
482                                 Emit (OpCodes.Stelem_Ref);
483                                 break;
484                         }
485                 }
486
487                 public void EmitInt (int i)
488                 {
489                         switch (i) {
490                         case -1:
491                                 ig.Emit (OpCodes.Ldc_I4_M1);
492                                 break;
493
494                         case 0:
495                                 ig.Emit (OpCodes.Ldc_I4_0);
496                                 break;
497
498                         case 1:
499                                 ig.Emit (OpCodes.Ldc_I4_1);
500                                 break;
501
502                         case 2:
503                                 ig.Emit (OpCodes.Ldc_I4_2);
504                                 break;
505
506                         case 3:
507                                 ig.Emit (OpCodes.Ldc_I4_3);
508                                 break;
509
510                         case 4:
511                                 ig.Emit (OpCodes.Ldc_I4_4);
512                                 break;
513
514                         case 5:
515                                 ig.Emit (OpCodes.Ldc_I4_5);
516                                 break;
517
518                         case 6:
519                                 ig.Emit (OpCodes.Ldc_I4_6);
520                                 break;
521
522                         case 7:
523                                 ig.Emit (OpCodes.Ldc_I4_7);
524                                 break;
525
526                         case 8:
527                                 ig.Emit (OpCodes.Ldc_I4_8);
528                                 break;
529
530                         default:
531                                 if (i >= -128 && i <= 127) {
532                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
533                                 } else
534                                         ig.Emit (OpCodes.Ldc_I4, i);
535                                 break;
536                         }
537                 }
538
539                 public void EmitLong (long l)
540                 {
541                         if (l >= int.MinValue && l <= int.MaxValue) {
542                                 EmitInt (unchecked ((int) l));
543                                 ig.Emit (OpCodes.Conv_I8);
544                                 return;
545                         }
546
547                         if (l >= 0 && l <= uint.MaxValue) {
548                                 EmitInt (unchecked ((int) l));
549                                 ig.Emit (OpCodes.Conv_U8);
550                                 return;
551                         }
552
553                         ig.Emit (OpCodes.Ldc_I8, l);
554                 }
555
556                 //
557                 // Load the object from the pointer.  
558                 //
559                 public void EmitLoadFromPtr (TypeSpec type)
560                 {
561                         if (type.Kind == MemberKind.Enum)
562                                 type = EnumSpec.GetUnderlyingType (type);
563
564                         switch (type.BuildinType) {
565                         case BuildinTypeSpec.Type.Int:
566                                 ig.Emit (OpCodes.Ldind_I4);
567                                 return;
568                         case BuildinTypeSpec.Type.UInt:
569                                 ig.Emit (OpCodes.Ldind_U4);
570                                 return;
571                         case BuildinTypeSpec.Type.Short:
572                                 ig.Emit (OpCodes.Ldind_I2);
573                                 return;
574                         case BuildinTypeSpec.Type.UShort:
575                         case BuildinTypeSpec.Type.Char:
576                                 ig.Emit (OpCodes.Ldind_U2);
577                                 return;
578                         case BuildinTypeSpec.Type.Byte:
579                                 ig.Emit (OpCodes.Ldind_U1);
580                                 return;
581                         case BuildinTypeSpec.Type.SByte:
582                         case BuildinTypeSpec.Type.Bool:
583                                 ig.Emit (OpCodes.Ldind_I1);
584                                 return;
585                         case BuildinTypeSpec.Type.ULong:
586                         case BuildinTypeSpec.Type.Long:
587                                 ig.Emit (OpCodes.Ldind_I8);
588                                 return;
589                         case BuildinTypeSpec.Type.Float:
590                                 ig.Emit (OpCodes.Ldind_R4);
591                                 return;
592                         case BuildinTypeSpec.Type.Double:
593                                 ig.Emit (OpCodes.Ldind_R8);
594                                 return;
595                         case BuildinTypeSpec.Type.IntPtr:
596                                 ig.Emit (OpCodes.Ldind_I);
597                                 return;
598                         }
599
600                         switch (type.Kind) {
601                         case MemberKind.Struct:
602                         case MemberKind.TypeParameter:
603                                 Emit (OpCodes.Ldobj, type);
604                                 break;
605                         case MemberKind.PointerType:
606                                 ig.Emit (OpCodes.Ldind_I);
607                                 break;
608                         default:
609                                 ig.Emit (OpCodes.Ldind_Ref);
610                                 break;
611                         }
612                 }
613
614                 //
615                 // The stack contains the pointer and the value of type `type'
616                 //
617                 public void EmitStoreFromPtr (TypeSpec type)
618                 {
619                         if (type.IsEnum)
620                                 type = EnumSpec.GetUnderlyingType (type);
621
622                         switch (type.BuildinType) {
623                         case BuildinTypeSpec.Type.Int:
624                         case BuildinTypeSpec.Type.UInt:
625                                 ig.Emit (OpCodes.Stind_I4);
626                                 return;
627                         case BuildinTypeSpec.Type.Long:
628                         case BuildinTypeSpec.Type.ULong:
629                                 ig.Emit (OpCodes.Stind_I8);
630                                 return;
631                         case BuildinTypeSpec.Type.Char:
632                         case BuildinTypeSpec.Type.Short:
633                         case BuildinTypeSpec.Type.UShort:
634                                 ig.Emit (OpCodes.Stind_I2);
635                                 return;
636                         case BuildinTypeSpec.Type.Float:
637                                 ig.Emit (OpCodes.Stind_R4);
638                                 return;
639                         case BuildinTypeSpec.Type.Double:
640                                 ig.Emit (OpCodes.Stind_R8);
641                                 return;
642                         case BuildinTypeSpec.Type.Byte:
643                         case BuildinTypeSpec.Type.SByte:
644                         case BuildinTypeSpec.Type.Bool:
645                                 ig.Emit (OpCodes.Stind_I1);
646                                 return;
647                         case BuildinTypeSpec.Type.IntPtr:
648                                 ig.Emit (OpCodes.Stind_I);
649                                 return;
650                         }
651
652                         if (type.IsStruct || TypeManager.IsGenericParameter (type))
653                                 Emit (OpCodes.Stobj, type);
654                         else
655                                 ig.Emit (OpCodes.Stind_Ref);
656                 }
657
658                 /// <summary>
659                 ///   Returns a temporary storage for a variable of type t as 
660                 ///   a local variable in the current body.
661                 /// </summary>
662                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
663                 {
664                         if (temporary_storage != null) {
665                                 object o;
666                                 if (temporary_storage.TryGetValue (t, out o)) {
667                                         if (o is Stack<LocalBuilder>) {
668                                                 var s = (Stack<LocalBuilder>) o;
669                                                 o = s.Count == 0 ? null : s.Pop ();
670                                         } else {
671                                                 temporary_storage.Remove (t);
672                                         }
673                                 }
674                                 if (o != null)
675                                         return (LocalBuilder) o;
676                         }
677                         return DeclareLocal (t, false);
678                 }
679
680                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
681                 {
682                         if (temporary_storage == null) {
683                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
684                                 temporary_storage.Add (t, b);
685                                 return;
686                         }
687                         object o;
688                         
689                         if (!temporary_storage.TryGetValue (t, out o)) {
690                                 temporary_storage.Add (t, b);
691                                 return;
692                         }
693                         var s = o as Stack<LocalBuilder>;
694                         if (s == null) {
695                                 s = new Stack<LocalBuilder> ();
696                                 s.Push ((LocalBuilder)o);
697                                 temporary_storage [t] = s;
698                         }
699                         s.Push (b);
700                 }
701
702                 /// <summary>
703                 ///   ReturnValue creates on demand the LocalBuilder for the
704                 ///   return value from the function.  By default this is not
705                 ///   used.  This is only required when returns are found inside
706                 ///   Try or Catch statements.
707                 ///
708                 ///   This method is typically invoked from the Emit phase, so
709                 ///   we allow the creation of a return label if it was not
710                 ///   requested during the resolution phase.   Could be cleaned
711                 ///   up, but it would replicate a lot of logic in the Emit phase
712                 ///   of the code that uses it.
713                 /// </summary>
714                 public LocalBuilder TemporaryReturn ()
715                 {
716                         if (return_value == null){
717                                 return_value = DeclareLocal (return_type, false);
718                                 if (!HasReturnLabel){
719                                         ReturnLabel = DefineLabel ();
720                                         HasReturnLabel = true;
721                                 }
722                         }
723
724                         return return_value;
725                 }
726         }
727 }