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