[Socket] Improved ConnectAsync
[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 BuiltinTypes BuiltinTypes {
105                         get {
106                                 return MemberContext.Module.Compiler.BuiltinTypes;
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                 public 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                 internal 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                                 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
224                                 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
225                                 CurrentType.MemberCache.AddMember (inflated);
226                         }
227
228                         return dynamic_site_container;
229                 }
230
231                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
232                 {
233                         if (IsAnonymousStoreyMutateRequired)
234                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
235
236                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
237                 }
238
239                 public Label DefineLabel ()
240                 {
241                         return ig.DefineLabel ();
242                 }
243
244                 public void MarkLabel (Label label)
245                 {
246                         ig.MarkLabel (label);
247                 }
248
249                 public void Emit (OpCode opcode)
250                 {
251                         ig.Emit (opcode);
252                 }
253
254                 public void Emit (OpCode opcode, LocalBuilder local)
255                 {
256                         ig.Emit (opcode, local);
257                 }
258
259                 public void Emit (OpCode opcode, string arg)
260                 {
261                         ig.Emit (opcode, arg);
262                 }
263
264                 public void Emit (OpCode opcode, double arg)
265                 {
266                         ig.Emit (opcode, arg);
267                 }
268
269                 public void Emit (OpCode opcode, float arg)
270                 {
271                         ig.Emit (opcode, arg);
272                 }
273
274                 public void Emit (OpCode opcode, int arg)
275                 {
276                         ig.Emit (opcode, arg);
277                 }
278
279                 public void Emit (OpCode opcode, byte arg)
280                 {
281                         ig.Emit (opcode, arg);
282                 }
283
284                 public void Emit (OpCode opcode, Label label)
285                 {
286                         ig.Emit (opcode, label);
287                 }
288
289                 public void Emit (OpCode opcode, Label[] labels)
290                 {
291                         ig.Emit (opcode, labels);
292                 }
293
294                 public void Emit (OpCode opcode, TypeSpec type)
295                 {
296                         if (IsAnonymousStoreyMutateRequired)
297                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
298
299                         ig.Emit (opcode, type.GetMetaInfo ());
300                 }
301
302                 public void Emit (OpCode opcode, FieldSpec field)
303                 {
304                         if (IsAnonymousStoreyMutateRequired)
305                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
306
307                         ig.Emit (opcode, field.GetMetaInfo ());
308                 }
309
310                 public void Emit (OpCode opcode, MethodSpec method)
311                 {
312                         if (IsAnonymousStoreyMutateRequired)
313                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
314
315                         if (method.IsConstructor)
316                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
317                         else
318                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
319                 }
320
321                 // TODO: REMOVE breaks mutator
322                 public void Emit (OpCode opcode, MethodInfo method)
323                 {
324                         ig.Emit (opcode, method);
325                 }
326
327                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
328                 {
329                         // TODO MemberCache: This should mutate too
330                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
331                 }
332
333                 public void EmitArrayNew (ArrayContainer ac)
334                 {
335                         if (ac.Rank == 1) {
336                                 Emit (OpCodes.Newarr, ac.Element);
337                         } else {
338                                 if (IsAnonymousStoreyMutateRequired)
339                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
340
341                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
342                         }
343                 }
344
345                 public void EmitArrayAddress (ArrayContainer ac)
346                 {
347                         if (ac.Rank > 1) {
348                                 if (IsAnonymousStoreyMutateRequired)
349                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
350
351                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
352                         } else {
353                                 Emit (OpCodes.Ldelema, ac.Element);
354                         }
355                 }
356
357                 //
358                 // Emits the right opcode to load from an array
359                 //
360                 public void EmitArrayLoad (ArrayContainer ac)
361                 {
362                         if (ac.Rank > 1) {
363                                 if (IsAnonymousStoreyMutateRequired)
364                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
365
366                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
367                                 return;
368                         }
369
370                         var type = ac.Element;
371                         if (type.Kind == MemberKind.Enum)
372                                 type = EnumSpec.GetUnderlyingType (type);
373
374                         switch (type.BuiltinType) {
375                         case BuiltinTypeSpec.Type.Byte:
376                         case BuiltinTypeSpec.Type.Bool:
377                                 Emit (OpCodes.Ldelem_U1);
378                                 return;
379                         case BuiltinTypeSpec.Type.SByte:
380                                 Emit (OpCodes.Ldelem_I1);
381                                 return;
382                         case BuiltinTypeSpec.Type.Short:
383                                 Emit (OpCodes.Ldelem_I2);
384                                 return;
385                         case BuiltinTypeSpec.Type.UShort:
386                         case BuiltinTypeSpec.Type.Char:
387                                 Emit (OpCodes.Ldelem_U2);
388                                 return;
389                         case BuiltinTypeSpec.Type.Int:
390                                 Emit (OpCodes.Ldelem_I4);
391                                 return;
392                         case BuiltinTypeSpec.Type.UInt:
393                                 Emit (OpCodes.Ldelem_U4);
394                                 return;
395                         case BuiltinTypeSpec.Type.ULong:
396                         case BuiltinTypeSpec.Type.Long:
397                                 Emit (OpCodes.Ldelem_I8);
398                                 return;
399                         case BuiltinTypeSpec.Type.Float:
400                                 Emit (OpCodes.Ldelem_R4);
401                                 return;
402                         case BuiltinTypeSpec.Type.Double:
403                                 Emit (OpCodes.Ldelem_R8);
404                                 return;
405                         case BuiltinTypeSpec.Type.IntPtr:
406                                 Emit (OpCodes.Ldelem_I);
407                                 return;
408                         }
409
410                         switch (type.Kind) {
411                         case MemberKind.Struct:
412                                 Emit (OpCodes.Ldelema, type);
413                                 Emit (OpCodes.Ldobj, type);
414                                 break;
415                         case MemberKind.TypeParameter:
416                                 Emit (OpCodes.Ldelem, type);
417                                 break;
418                         case MemberKind.PointerType:
419                                 Emit (OpCodes.Ldelem_I);
420                                 break;
421                         default:
422                                 Emit (OpCodes.Ldelem_Ref);
423                                 break;
424                         }
425                 }
426
427                 //
428                 // Emits the right opcode to store to an array
429                 //
430                 public void EmitArrayStore (ArrayContainer ac)
431                 {
432                         if (ac.Rank > 1) {
433                                 if (IsAnonymousStoreyMutateRequired)
434                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
435
436                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
437                                 return;
438                         }
439
440                         var type = ac.Element;
441
442                         if (type.Kind == MemberKind.Enum)
443                                 type = EnumSpec.GetUnderlyingType (type);
444
445                         switch (type.BuiltinType) {
446                         case BuiltinTypeSpec.Type.Byte:
447                         case BuiltinTypeSpec.Type.SByte:
448                         case BuiltinTypeSpec.Type.Bool:
449                                 Emit (OpCodes.Stelem_I1);
450                                 return;
451                         case BuiltinTypeSpec.Type.Short:
452                         case BuiltinTypeSpec.Type.UShort:
453                         case BuiltinTypeSpec.Type.Char:
454                                 Emit (OpCodes.Stelem_I2);
455                                 return;
456                         case BuiltinTypeSpec.Type.Int:
457                         case BuiltinTypeSpec.Type.UInt:
458                                 Emit (OpCodes.Stelem_I4);
459                                 return;
460                         case BuiltinTypeSpec.Type.Long:
461                         case BuiltinTypeSpec.Type.ULong:
462                                 Emit (OpCodes.Stelem_I8);
463                                 return;
464                         case BuiltinTypeSpec.Type.Float:
465                                 Emit (OpCodes.Stelem_R4);
466                                 return;
467                         case BuiltinTypeSpec.Type.Double:
468                                 Emit (OpCodes.Stelem_R8);
469                                 return;
470                         }
471
472                         switch (type.Kind) {
473                         case MemberKind.Struct:
474                                 Emit (OpCodes.Stobj, type);
475                                 break;
476                         case MemberKind.TypeParameter:
477                                 Emit (OpCodes.Stelem, type);
478                                 break;
479                         case MemberKind.PointerType:
480                                 Emit (OpCodes.Stelem_I);
481                                 break;
482                         default:
483                                 Emit (OpCodes.Stelem_Ref);
484                                 break;
485                         }
486                 }
487
488                 public void EmitInt (int i)
489                 {
490                         switch (i) {
491                         case -1:
492                                 ig.Emit (OpCodes.Ldc_I4_M1);
493                                 break;
494
495                         case 0:
496                                 ig.Emit (OpCodes.Ldc_I4_0);
497                                 break;
498
499                         case 1:
500                                 ig.Emit (OpCodes.Ldc_I4_1);
501                                 break;
502
503                         case 2:
504                                 ig.Emit (OpCodes.Ldc_I4_2);
505                                 break;
506
507                         case 3:
508                                 ig.Emit (OpCodes.Ldc_I4_3);
509                                 break;
510
511                         case 4:
512                                 ig.Emit (OpCodes.Ldc_I4_4);
513                                 break;
514
515                         case 5:
516                                 ig.Emit (OpCodes.Ldc_I4_5);
517                                 break;
518
519                         case 6:
520                                 ig.Emit (OpCodes.Ldc_I4_6);
521                                 break;
522
523                         case 7:
524                                 ig.Emit (OpCodes.Ldc_I4_7);
525                                 break;
526
527                         case 8:
528                                 ig.Emit (OpCodes.Ldc_I4_8);
529                                 break;
530
531                         default:
532                                 if (i >= -128 && i <= 127) {
533                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
534                                 } else
535                                         ig.Emit (OpCodes.Ldc_I4, i);
536                                 break;
537                         }
538                 }
539
540                 public void EmitLong (long l)
541                 {
542                         if (l >= int.MinValue && l <= int.MaxValue) {
543                                 EmitInt (unchecked ((int) l));
544                                 ig.Emit (OpCodes.Conv_I8);
545                                 return;
546                         }
547
548                         if (l >= 0 && l <= uint.MaxValue) {
549                                 EmitInt (unchecked ((int) l));
550                                 ig.Emit (OpCodes.Conv_U8);
551                                 return;
552                         }
553
554                         ig.Emit (OpCodes.Ldc_I8, l);
555                 }
556
557                 //
558                 // Load the object from the pointer.  
559                 //
560                 public void EmitLoadFromPtr (TypeSpec type)
561                 {
562                         if (type.Kind == MemberKind.Enum)
563                                 type = EnumSpec.GetUnderlyingType (type);
564
565                         switch (type.BuiltinType) {
566                         case BuiltinTypeSpec.Type.Int:
567                                 ig.Emit (OpCodes.Ldind_I4);
568                                 return;
569                         case BuiltinTypeSpec.Type.UInt:
570                                 ig.Emit (OpCodes.Ldind_U4);
571                                 return;
572                         case BuiltinTypeSpec.Type.Short:
573                                 ig.Emit (OpCodes.Ldind_I2);
574                                 return;
575                         case BuiltinTypeSpec.Type.UShort:
576                         case BuiltinTypeSpec.Type.Char:
577                                 ig.Emit (OpCodes.Ldind_U2);
578                                 return;
579                         case BuiltinTypeSpec.Type.Byte:
580                                 ig.Emit (OpCodes.Ldind_U1);
581                                 return;
582                         case BuiltinTypeSpec.Type.SByte:
583                         case BuiltinTypeSpec.Type.Bool:
584                                 ig.Emit (OpCodes.Ldind_I1);
585                                 return;
586                         case BuiltinTypeSpec.Type.ULong:
587                         case BuiltinTypeSpec.Type.Long:
588                                 ig.Emit (OpCodes.Ldind_I8);
589                                 return;
590                         case BuiltinTypeSpec.Type.Float:
591                                 ig.Emit (OpCodes.Ldind_R4);
592                                 return;
593                         case BuiltinTypeSpec.Type.Double:
594                                 ig.Emit (OpCodes.Ldind_R8);
595                                 return;
596                         case BuiltinTypeSpec.Type.IntPtr:
597                                 ig.Emit (OpCodes.Ldind_I);
598                                 return;
599                         }
600
601                         switch (type.Kind) {
602                         case MemberKind.Struct:
603                         case MemberKind.TypeParameter:
604                                 Emit (OpCodes.Ldobj, type);
605                                 break;
606                         case MemberKind.PointerType:
607                                 ig.Emit (OpCodes.Ldind_I);
608                                 break;
609                         default:
610                                 ig.Emit (OpCodes.Ldind_Ref);
611                                 break;
612                         }
613                 }
614
615                 //
616                 // The stack contains the pointer and the value of type `type'
617                 //
618                 public void EmitStoreFromPtr (TypeSpec type)
619                 {
620                         if (type.IsEnum)
621                                 type = EnumSpec.GetUnderlyingType (type);
622
623                         switch (type.BuiltinType) {
624                         case BuiltinTypeSpec.Type.Int:
625                         case BuiltinTypeSpec.Type.UInt:
626                                 ig.Emit (OpCodes.Stind_I4);
627                                 return;
628                         case BuiltinTypeSpec.Type.Long:
629                         case BuiltinTypeSpec.Type.ULong:
630                                 ig.Emit (OpCodes.Stind_I8);
631                                 return;
632                         case BuiltinTypeSpec.Type.Char:
633                         case BuiltinTypeSpec.Type.Short:
634                         case BuiltinTypeSpec.Type.UShort:
635                                 ig.Emit (OpCodes.Stind_I2);
636                                 return;
637                         case BuiltinTypeSpec.Type.Float:
638                                 ig.Emit (OpCodes.Stind_R4);
639                                 return;
640                         case BuiltinTypeSpec.Type.Double:
641                                 ig.Emit (OpCodes.Stind_R8);
642                                 return;
643                         case BuiltinTypeSpec.Type.Byte:
644                         case BuiltinTypeSpec.Type.SByte:
645                         case BuiltinTypeSpec.Type.Bool:
646                                 ig.Emit (OpCodes.Stind_I1);
647                                 return;
648                         case BuiltinTypeSpec.Type.IntPtr:
649                                 ig.Emit (OpCodes.Stind_I);
650                                 return;
651                         }
652
653                         if (type.IsStruct || TypeManager.IsGenericParameter (type))
654                                 Emit (OpCodes.Stobj, type);
655                         else
656                                 ig.Emit (OpCodes.Stind_Ref);
657                 }
658
659                 /// <summary>
660                 ///   Returns a temporary storage for a variable of type t as 
661                 ///   a local variable in the current body.
662                 /// </summary>
663                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
664                 {
665                         if (temporary_storage != null) {
666                                 object o;
667                                 if (temporary_storage.TryGetValue (t, out o)) {
668                                         if (o is Stack<LocalBuilder>) {
669                                                 var s = (Stack<LocalBuilder>) o;
670                                                 o = s.Count == 0 ? null : s.Pop ();
671                                         } else {
672                                                 temporary_storage.Remove (t);
673                                         }
674                                 }
675                                 if (o != null)
676                                         return (LocalBuilder) o;
677                         }
678                         return DeclareLocal (t, false);
679                 }
680
681                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
682                 {
683                         if (temporary_storage == null) {
684                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
685                                 temporary_storage.Add (t, b);
686                                 return;
687                         }
688                         object o;
689                         
690                         if (!temporary_storage.TryGetValue (t, out o)) {
691                                 temporary_storage.Add (t, b);
692                                 return;
693                         }
694                         var s = o as Stack<LocalBuilder>;
695                         if (s == null) {
696                                 s = new Stack<LocalBuilder> ();
697                                 s.Push ((LocalBuilder)o);
698                                 temporary_storage [t] = s;
699                         }
700                         s.Push (b);
701                 }
702
703                 /// <summary>
704                 ///   ReturnValue creates on demand the LocalBuilder for the
705                 ///   return value from the function.  By default this is not
706                 ///   used.  This is only required when returns are found inside
707                 ///   Try or Catch statements.
708                 ///
709                 ///   This method is typically invoked from the Emit phase, so
710                 ///   we allow the creation of a return label if it was not
711                 ///   requested during the resolution phase.   Could be cleaned
712                 ///   up, but it would replicate a lot of logic in the Emit phase
713                 ///   of the code that uses it.
714                 /// </summary>
715                 public LocalBuilder TemporaryReturn ()
716                 {
717                         if (return_value == null){
718                                 return_value = DeclareLocal (return_type, false);
719                                 if (!HasReturnLabel){
720                                         ReturnLabel = DefineLabel ();
721                                         HasReturnLabel = true;
722                                 }
723                         }
724
725                         return return_value;
726                 }
727         }
728 }