Merge pull request #1266 from esdrubal/datetimenewformat
[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 // Copyright 2011 Xamarin Inc
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using Mono.CompilerServices.SymbolWriter;
16
17 #if STATIC
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
21 #else
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
25 #endif
26
27 namespace Mono.CSharp
28 {
29         /// <summary>
30         ///   An Emit Context is created for each body of code (from methods,
31         ///   properties bodies, indexer bodies or constructor bodies)
32         /// </summary>
33         public class EmitContext : BuilderContext
34         {
35                 // TODO: Has to be private
36                 public readonly ILGenerator ig;
37
38                 /// <summary>
39                 ///   The value that is allowed to be returned or NULL if there is no
40                 ///   return type.
41                 /// </summary>
42                 readonly TypeSpec return_type;
43
44                 /// <summary>
45                 ///   Keeps track of the Type to LocalBuilder temporary storage created
46                 ///   to store structures (used to compute the address of the structure
47                 ///   value on structure method invocations)
48                 /// </summary>
49                 Dictionary<TypeSpec, object> temporary_storage;
50
51                 /// <summary>
52                 ///   The location where we store the return value.
53                 /// </summary>
54                 public LocalBuilder return_value;
55
56
57                 /// <summary>
58                 ///   Current loop begin and end labels.
59                 /// </summary>
60                 public Label LoopBegin, LoopEnd;
61
62                 /// <summary>
63                 ///   Default target in a switch statement.   Only valid if
64                 ///   InSwitch is true
65                 /// </summary>
66                 public Label DefaultTarget;
67
68                 /// <summary>
69                 ///   If this is non-null, points to the current switch statement
70                 /// </summary>
71                 public Switch Switch;
72
73                 /// <summary>
74                 ///  Whether we are inside an anonymous method.
75                 /// </summary>
76                 public AnonymousExpression CurrentAnonymousMethod;
77                 
78                 readonly IMemberContext member_context;
79
80                 readonly SourceMethodBuilder methodSymbols;
81
82                 DynamicSiteClass dynamic_site_container;
83
84                 Label? return_label;
85
86                 List<IExpressionCleanup> epilogue_expressions;
87
88                 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type, SourceMethodBuilder methodSymbols)
89                 {
90                         this.member_context = rc;
91                         this.ig = ig;
92                         this.return_type = return_type;
93
94                         if (rc.Module.Compiler.Settings.Checked)
95                                 flags |= Options.CheckedScope;
96
97                         if (methodSymbols != null) {
98                                 this.methodSymbols = methodSymbols;
99                                 if (!rc.Module.Compiler.Settings.Optimize)
100                                         flags |= Options.AccurateDebugInfo;
101                         } else {
102                                 flags |= Options.OmitDebugInfo;
103                         }
104
105 #if STATIC
106                         ig.__CleverExceptionBlockAssistance ();
107 #endif
108                 }
109
110                 #region Properties
111
112                 internal AsyncTaskStorey AsyncTaskStorey {
113                         get {
114                                 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
115                         }
116                 }
117
118                 public BuiltinTypes BuiltinTypes {
119                         get {
120                                 return MemberContext.Module.Compiler.BuiltinTypes;
121                         }
122                 }
123
124                 public ConditionalAccessContext ConditionalAccess { get; set; }
125
126                 public TypeSpec CurrentType {
127                         get { return member_context.CurrentType; }
128                 }
129
130                 public TypeParameters CurrentTypeParameters {
131                     get { return member_context.CurrentTypeParameters; }
132                 }
133
134                 public MemberCore CurrentTypeDefinition {
135                         get { return member_context.CurrentMemberDefinition; }
136                 }
137
138                 public bool EmitAccurateDebugInfo {
139                         get {
140                                 return (flags & Options.AccurateDebugInfo) != 0;
141                         }
142                 }
143
144                 public bool HasMethodSymbolBuilder {
145                         get {
146                                 return methodSymbols != null;
147                         }
148                 }
149
150                 public bool HasReturnLabel {
151                         get {
152                                 return return_label.HasValue;
153                         }
154                 }
155
156                 public bool IsStatic {
157                         get { return member_context.IsStatic; }
158                 }
159
160                 public bool IsStaticConstructor {
161                         get {
162                                 return member_context.IsStatic && (flags & Options.ConstructorScope) != 0;
163                         }
164                 }
165
166                 public bool IsAnonymousStoreyMutateRequired {
167                         get {
168                                 return CurrentAnonymousMethod != null &&
169                                         CurrentAnonymousMethod.Storey != null &&
170                                         CurrentAnonymousMethod.Storey.Mutator != null;
171                         }
172                 }
173
174                 public IMemberContext MemberContext {
175                         get {
176                                 return member_context;
177                         }
178                 }
179
180                 public ModuleContainer Module {
181                         get {
182                                 return member_context.Module;
183                         }
184                 }
185
186                 public bool NotifyEvaluatorOnStore {
187                         get {
188                                 return Module.Evaluator != null && Module.Evaluator.ModificationListener != null;
189                         }
190                 }
191
192                 // Has to be used for specific emitter errors only any
193                 // possible resolver errors have to be reported during Resolve
194                 public Report Report {
195                         get {
196                                 return member_context.Module.Compiler.Report;
197                         }
198                 }
199
200                 public TypeSpec ReturnType {
201                         get {
202                                 return return_type;
203                         }
204                 }
205
206                 //
207                 // The label where we have to jump before leaving the context
208                 //
209                 public Label ReturnLabel {
210                         get {
211                                 return return_label.Value;
212                         }
213                 }
214
215                 public List<IExpressionCleanup> StatementEpilogue {
216                         get {
217                                 return epilogue_expressions;
218                         }
219                 }
220
221                 public LocalVariable AsyncThrowVariable { get; set; }
222
223                 public List<TryFinally> TryFinallyUnwind { get; set; }
224
225                 public Label RecursivePatternLabel { get; set; }
226
227                 #endregion
228
229                 public void AddStatementEpilog (IExpressionCleanup cleanupExpression)
230                 {
231                         if (epilogue_expressions == null) {
232                                 epilogue_expressions = new List<IExpressionCleanup> ();
233                         } else if (epilogue_expressions.Contains (cleanupExpression)) {
234                                 return;
235                         }
236
237                         epilogue_expressions.Add (cleanupExpression);
238                 }
239
240                 public void AssertEmptyStack ()
241                 {
242 #if STATIC
243                         if (ig.__StackHeight != 0)
244                                 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
245                                         member_context.GetSignatureForError ());
246 #endif
247                 }
248
249                 /// <summary>
250                 ///   This is called immediately before emitting an IL opcode to tell the symbol
251                 ///   writer to which source line this opcode belongs.
252                 /// </summary>
253                 public bool Mark (Location loc)
254                 {
255                         if ((flags & Options.OmitDebugInfo) != 0)
256                                 return false;
257
258                         if (loc.IsNull || methodSymbols == null)
259                                 return false;
260
261                         var sf = loc.SourceFile;
262                         if (sf.IsHiddenLocation (loc))
263                                 return false;
264
265 #if NET_4_0
266                         methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
267 #endif
268                         return true;
269                 }
270
271                 public void MarkCallEntry (Location loc)
272                 {
273                         if (!EmitAccurateDebugInfo)
274                                 return;
275
276                         //
277                         // TODO: This should emit different kind of sequence point to make
278                         // step-over work for statement over multiple lines
279                         //
280                         // Debugging experience for Foo (A () + B ()) where A and B are
281                         // on separate lines is not great
282                         //
283                         Mark (loc);
284                 }
285
286                 public void DefineLocalVariable (string name, LocalBuilder builder)
287                 {
288                         if ((flags & Options.OmitDebugInfo) != 0)
289                                 return;
290
291                         methodSymbols.AddLocal (builder.LocalIndex, name);
292                 }
293
294                 public void BeginCatchBlock (TypeSpec type)
295                 {
296                         if (IsAnonymousStoreyMutateRequired)
297                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
298
299                         ig.BeginCatchBlock (type.GetMetaInfo ());
300                 }
301
302                 public void BeginFilterHandler ()
303                 {
304                         ig.BeginCatchBlock (null);
305                 }
306
307                 public void BeginExceptionBlock ()
308                 {
309                         ig.BeginExceptionBlock ();
310                 }
311
312                 public void BeginExceptionFilterBlock ()
313                 {
314                         ig.BeginExceptFilterBlock ();
315                 }
316
317                 public void BeginFinallyBlock ()
318                 {
319                         ig.BeginFinallyBlock ();
320                 }
321
322                 public void BeginScope ()
323                 {
324                         if ((flags & Options.OmitDebugInfo) != 0)
325                                 return;
326
327 #if NET_4_0
328                         methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
329 #endif
330                 }
331
332                 public void BeginCompilerScope ()
333                 {
334                         if ((flags & Options.OmitDebugInfo) != 0)
335                                 return;
336
337 #if NET_4_0
338                         methodSymbols.StartBlock (CodeBlockEntry.Type.CompilerGenerated, ig.ILOffset);
339 #endif
340                 }
341
342                 public void EndExceptionBlock ()
343                 {
344                         ig.EndExceptionBlock ();
345                 }
346
347                 public void EndScope ()
348                 {
349                         if ((flags & Options.OmitDebugInfo) != 0)
350                                 return;
351
352 #if NET_4_0
353                         methodSymbols.EndBlock (ig.ILOffset);
354 #endif
355                 }
356
357                 public void CloseConditionalAccess (TypeSpec type)
358                 {
359                         if (type != null)
360                                 Emit (OpCodes.Newobj, Nullable.NullableInfo.GetConstructor (type));
361
362                         MarkLabel (ConditionalAccess.EndLabel);
363                         ConditionalAccess = null;
364                 }
365
366                 //
367                 // Creates a nested container in this context for all dynamic compiler generated stuff
368                 //
369                 internal DynamicSiteClass CreateDynamicSite ()
370                 {
371                         if (dynamic_site_container == null) {
372                                 var mc = member_context.CurrentMemberDefinition as MemberBase;
373                                 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
374
375                                 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
376                                 dynamic_site_container.CreateContainer ();
377                                 dynamic_site_container.DefineContainer ();
378                                 dynamic_site_container.Define ();
379
380                                 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
381                                 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
382                                 CurrentType.MemberCache.AddMember (inflated);
383                         }
384
385                         return dynamic_site_container;
386                 }
387
388                 public Label CreateReturnLabel ()
389                 {
390                         if (!return_label.HasValue)
391                                 return_label = DefineLabel ();
392
393                         return return_label.Value;
394                 }
395
396                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
397                 {
398                         if (IsAnonymousStoreyMutateRequired)
399                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
400
401                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
402                 }
403
404                 public Label DefineLabel ()
405                 {
406                         return ig.DefineLabel ();
407                 }
408
409                 //
410                 // Creates temporary field in current async storey
411                 //
412                 public StackFieldExpr GetTemporaryField (TypeSpec type, bool initializedFieldRequired = false)
413                 {
414                         var f = AsyncTaskStorey.AddCapturedLocalVariable (type, initializedFieldRequired);
415                         var fexpr = new StackFieldExpr (f);
416                         fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
417                         return fexpr;
418                 }
419
420                 public void MarkLabel (Label label)
421                 {
422                         ig.MarkLabel (label);
423                 }
424
425                 public void Emit (OpCode opcode)
426                 {
427                         ig.Emit (opcode);
428                 }
429
430                 public void Emit (OpCode opcode, LocalBuilder local)
431                 {
432                         ig.Emit (opcode, local);
433                 }
434
435                 public void Emit (OpCode opcode, string arg)
436                 {
437                         ig.Emit (opcode, arg);
438                 }
439
440                 public void Emit (OpCode opcode, double arg)
441                 {
442                         ig.Emit (opcode, arg);
443                 }
444
445                 public void Emit (OpCode opcode, float arg)
446                 {
447                         ig.Emit (opcode, arg);
448                 }
449
450                 public void Emit (OpCode opcode, Label label)
451                 {
452                         ig.Emit (opcode, label);
453                 }
454
455                 public void Emit (OpCode opcode, Label[] labels)
456                 {
457                         ig.Emit (opcode, labels);
458                 }
459
460                 public void Emit (OpCode opcode, TypeSpec type)
461                 {
462                         if (IsAnonymousStoreyMutateRequired)
463                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
464
465                         ig.Emit (opcode, type.GetMetaInfo ());
466                 }
467
468                 public void Emit (OpCode opcode, FieldSpec field)
469                 {
470                         if (IsAnonymousStoreyMutateRequired)
471                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
472
473                         ig.Emit (opcode, field.GetMetaInfo ());
474                 }
475
476                 public void Emit (OpCode opcode, MethodSpec method)
477                 {
478                         if (IsAnonymousStoreyMutateRequired)
479                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
480
481                         if (method.IsConstructor)
482                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
483                         else
484                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
485                 }
486
487                 // TODO: REMOVE breaks mutator
488                 public void Emit (OpCode opcode, MethodInfo method)
489                 {
490                         ig.Emit (opcode, method);
491                 }
492
493                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
494                 {
495                         // TODO MemberCache: This should mutate too
496                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
497                 }
498
499                 public void EmitArrayNew (ArrayContainer ac)
500                 {
501                         if (ac.Rank == 1) {
502                                 var type = IsAnonymousStoreyMutateRequired ?
503                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
504                                         ac.Element;
505
506                                 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
507                         } else {
508                                 if (IsAnonymousStoreyMutateRequired)
509                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
510
511                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
512                         }
513                 }
514
515                 public void EmitArrayAddress (ArrayContainer ac)
516                 {
517                         if (ac.Rank > 1) {
518                                 if (IsAnonymousStoreyMutateRequired)
519                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
520
521                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
522                         } else {
523                                 var type = IsAnonymousStoreyMutateRequired ?
524                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
525                                         ac.Element;
526
527                                 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
528                         }
529                 }
530
531                 //
532                 // Emits the right opcode to load from an array
533                 //
534                 public void EmitArrayLoad (ArrayContainer ac)
535                 {
536                         if (ac.Rank > 1) {
537                                 if (IsAnonymousStoreyMutateRequired)
538                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
539
540                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
541                                 return;
542                         }
543
544
545                         var type = ac.Element;
546                         if (type.Kind == MemberKind.Enum)
547                                 type = EnumSpec.GetUnderlyingType (type);
548
549                         switch (type.BuiltinType) {
550                         case BuiltinTypeSpec.Type.Bool:
551                                 //
552                                 // Workaround MSIL limitation. Load bool element as single bit,
553                                 // bool array can actually store any byte value
554                                 //
555                                 ig.Emit (OpCodes.Ldelem_U1);
556                                 ig.Emit (OpCodes.Ldc_I4_0);
557                                 ig.Emit (OpCodes.Cgt_Un);
558                                 break;
559                         case BuiltinTypeSpec.Type.Byte:
560                                 ig.Emit (OpCodes.Ldelem_U1);
561                                 break;
562                         case BuiltinTypeSpec.Type.SByte:
563                                 ig.Emit (OpCodes.Ldelem_I1);
564                                 break;
565                         case BuiltinTypeSpec.Type.Short:
566                                 ig.Emit (OpCodes.Ldelem_I2);
567                                 break;
568                         case BuiltinTypeSpec.Type.UShort:
569                         case BuiltinTypeSpec.Type.Char:
570                                 ig.Emit (OpCodes.Ldelem_U2);
571                                 break;
572                         case BuiltinTypeSpec.Type.Int:
573                                 ig.Emit (OpCodes.Ldelem_I4);
574                                 break;
575                         case BuiltinTypeSpec.Type.UInt:
576                                 ig.Emit (OpCodes.Ldelem_U4);
577                                 break;
578                         case BuiltinTypeSpec.Type.ULong:
579                         case BuiltinTypeSpec.Type.Long:
580                                 ig.Emit (OpCodes.Ldelem_I8);
581                                 break;
582                         case BuiltinTypeSpec.Type.Float:
583                                 ig.Emit (OpCodes.Ldelem_R4);
584                                 break;
585                         case BuiltinTypeSpec.Type.Double:
586                                 ig.Emit (OpCodes.Ldelem_R8);
587                                 break;
588                         case BuiltinTypeSpec.Type.IntPtr:
589                                 ig.Emit (OpCodes.Ldelem_I);
590                                 break;
591                         default:
592                                 switch (type.Kind) {
593                                 case MemberKind.Struct:
594                                         if (IsAnonymousStoreyMutateRequired)
595                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
596
597                                         ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
598                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
599                                         break;
600                                 case MemberKind.TypeParameter:
601                                         if (IsAnonymousStoreyMutateRequired)
602                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
603
604                                         ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
605                                         break;
606                                 case MemberKind.PointerType:
607                                         ig.Emit (OpCodes.Ldelem_I);
608                                         break;
609                                 default:
610                                         ig.Emit (OpCodes.Ldelem_Ref);
611                                         break;
612                                 }
613                                 break;
614                         }
615                 }
616
617                 //
618                 // Emits the right opcode to store to an array
619                 //
620                 public void EmitArrayStore (ArrayContainer ac)
621                 {
622                         if (ac.Rank > 1) {
623                                 if (IsAnonymousStoreyMutateRequired)
624                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
625
626                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
627                                 return;
628                         }
629
630                         var type = ac.Element;
631
632                         if (type.Kind == MemberKind.Enum)
633                                 type = EnumSpec.GetUnderlyingType (type);
634
635                         switch (type.BuiltinType) {
636                         case BuiltinTypeSpec.Type.Byte:
637                         case BuiltinTypeSpec.Type.SByte:
638                         case BuiltinTypeSpec.Type.Bool:
639                                 Emit (OpCodes.Stelem_I1);
640                                 return;
641                         case BuiltinTypeSpec.Type.Short:
642                         case BuiltinTypeSpec.Type.UShort:
643                         case BuiltinTypeSpec.Type.Char:
644                                 Emit (OpCodes.Stelem_I2);
645                                 return;
646                         case BuiltinTypeSpec.Type.Int:
647                         case BuiltinTypeSpec.Type.UInt:
648                                 Emit (OpCodes.Stelem_I4);
649                                 return;
650                         case BuiltinTypeSpec.Type.Long:
651                         case BuiltinTypeSpec.Type.ULong:
652                                 Emit (OpCodes.Stelem_I8);
653                                 return;
654                         case BuiltinTypeSpec.Type.Float:
655                                 Emit (OpCodes.Stelem_R4);
656                                 return;
657                         case BuiltinTypeSpec.Type.Double:
658                                 Emit (OpCodes.Stelem_R8);
659                                 return;
660                         }
661
662                         switch (type.Kind) {
663                         case MemberKind.Struct:
664                                 Emit (OpCodes.Stobj, type);
665                                 break;
666                         case MemberKind.TypeParameter:
667                                 Emit (OpCodes.Stelem, type);
668                                 break;
669                         case MemberKind.PointerType:
670                                 Emit (OpCodes.Stelem_I);
671                                 break;
672                         default:
673                                 Emit (OpCodes.Stelem_Ref);
674                                 break;
675                         }
676                 }
677
678                 public void EmitInt (int i)
679                 {
680                         EmitIntConstant (i);
681                 }
682
683                 void EmitIntConstant (int i)
684                 {
685                         switch (i) {
686                         case -1:
687                                 ig.Emit (OpCodes.Ldc_I4_M1);
688                                 break;
689
690                         case 0:
691                                 ig.Emit (OpCodes.Ldc_I4_0);
692                                 break;
693
694                         case 1:
695                                 ig.Emit (OpCodes.Ldc_I4_1);
696                                 break;
697
698                         case 2:
699                                 ig.Emit (OpCodes.Ldc_I4_2);
700                                 break;
701
702                         case 3:
703                                 ig.Emit (OpCodes.Ldc_I4_3);
704                                 break;
705
706                         case 4:
707                                 ig.Emit (OpCodes.Ldc_I4_4);
708                                 break;
709
710                         case 5:
711                                 ig.Emit (OpCodes.Ldc_I4_5);
712                                 break;
713
714                         case 6:
715                                 ig.Emit (OpCodes.Ldc_I4_6);
716                                 break;
717
718                         case 7:
719                                 ig.Emit (OpCodes.Ldc_I4_7);
720                                 break;
721
722                         case 8:
723                                 ig.Emit (OpCodes.Ldc_I4_8);
724                                 break;
725
726                         default:
727                                 if (i >= -128 && i <= 127) {
728                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
729                                 } else
730                                         ig.Emit (OpCodes.Ldc_I4, i);
731                                 break;
732                         }
733                 }
734
735                 public void EmitLong (long l)
736                 {
737                         if (l >= int.MinValue && l <= int.MaxValue) {
738                                 EmitIntConstant (unchecked ((int) l));
739                                 ig.Emit (OpCodes.Conv_I8);
740                         } else if (l >= 0 && l <= uint.MaxValue) {
741                                 EmitIntConstant (unchecked ((int) l));
742                                 ig.Emit (OpCodes.Conv_U8);
743                         } else {
744                                 ig.Emit (OpCodes.Ldc_I8, l);
745                         }
746                 }
747
748                 //
749                 // Load the object from the pointer.  
750                 //
751                 public void EmitLoadFromPtr (TypeSpec type)
752                 {
753                         if (type.Kind == MemberKind.Enum)
754                                 type = EnumSpec.GetUnderlyingType (type);
755
756                         switch (type.BuiltinType) {
757                         case BuiltinTypeSpec.Type.Int:
758                                 ig.Emit (OpCodes.Ldind_I4);
759                                 break;
760                         case BuiltinTypeSpec.Type.UInt:
761                                 ig.Emit (OpCodes.Ldind_U4);
762                                 break;
763                         case BuiltinTypeSpec.Type.Short:
764                                 ig.Emit (OpCodes.Ldind_I2);
765                                 break;
766                         case BuiltinTypeSpec.Type.UShort:
767                         case BuiltinTypeSpec.Type.Char:
768                                 ig.Emit (OpCodes.Ldind_U2);
769                                 break;
770                         case BuiltinTypeSpec.Type.Byte:
771                                 ig.Emit (OpCodes.Ldind_U1);
772                                 break;
773                         case BuiltinTypeSpec.Type.SByte:
774                                 ig.Emit (OpCodes.Ldind_I1);
775                                 break;
776                         case BuiltinTypeSpec.Type.Bool:
777                                 ig.Emit (OpCodes.Ldind_I1);
778                                 ig.Emit (OpCodes.Ldc_I4_0);
779                                 ig.Emit (OpCodes.Cgt_Un);
780                                 break;
781                         case BuiltinTypeSpec.Type.ULong:
782                         case BuiltinTypeSpec.Type.Long:
783                                 ig.Emit (OpCodes.Ldind_I8);
784                                 break;
785                         case BuiltinTypeSpec.Type.Float:
786                                 ig.Emit (OpCodes.Ldind_R4);
787                                 break;
788                         case BuiltinTypeSpec.Type.Double:
789                                 ig.Emit (OpCodes.Ldind_R8);
790                                 break;
791                         case BuiltinTypeSpec.Type.IntPtr:
792                                 ig.Emit (OpCodes.Ldind_I);
793                                 break;
794                         default:
795                                 switch (type.Kind) {
796                                 case MemberKind.Struct:
797                                 case MemberKind.TypeParameter:
798                                         if (IsAnonymousStoreyMutateRequired)
799                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
800
801                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
802                                         break;
803                                 case MemberKind.PointerType:
804                                         ig.Emit (OpCodes.Ldind_I);
805                                         break;
806                                 default:
807                                         ig.Emit (OpCodes.Ldind_Ref);
808                                         break;
809                                 }
810                                 break;
811                         }
812                 }
813
814                 public void EmitNull ()
815                 {
816                         ig.Emit (OpCodes.Ldnull);
817                 }
818
819                 public void EmitArgumentAddress (int pos)
820                 {
821                         if (!IsStatic)
822                                 ++pos;
823
824                         if (pos > byte.MaxValue)
825                                 ig.Emit (OpCodes.Ldarga, pos);
826                         else
827                                 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
828                 }
829
830                 public void EmitArgumentLoad (int pos)
831                 {
832                         if (!IsStatic)
833                                 ++pos;
834
835                         switch (pos) {
836                         case 0: ig.Emit (OpCodes.Ldarg_0); break;
837                         case 1: ig.Emit (OpCodes.Ldarg_1); break;
838                         case 2: ig.Emit (OpCodes.Ldarg_2); break;
839                         case 3: ig.Emit (OpCodes.Ldarg_3); break;
840                         default:
841                                 if (pos > byte.MaxValue)
842                                         ig.Emit (OpCodes.Ldarg, pos);
843                                 else
844                                         ig.Emit (OpCodes.Ldarg_S, (byte) pos);
845                                 break;
846                         }
847                 }
848
849                 public void EmitArgumentStore (int pos)
850                 {
851                         if (!IsStatic)
852                                 ++pos;
853
854                         if (pos > byte.MaxValue)
855                                 ig.Emit (OpCodes.Starg, pos);
856                         else
857                                 ig.Emit (OpCodes.Starg_S, (byte) pos);
858                 }
859
860                 //
861                 // The stack contains the pointer and the value of type `type'
862                 //
863                 public void EmitStoreFromPtr (TypeSpec type)
864                 {
865                         if (type.IsEnum)
866                                 type = EnumSpec.GetUnderlyingType (type);
867
868                         switch (type.BuiltinType) {
869                         case BuiltinTypeSpec.Type.Int:
870                         case BuiltinTypeSpec.Type.UInt:
871                                 ig.Emit (OpCodes.Stind_I4);
872                                 return;
873                         case BuiltinTypeSpec.Type.Long:
874                         case BuiltinTypeSpec.Type.ULong:
875                                 ig.Emit (OpCodes.Stind_I8);
876                                 return;
877                         case BuiltinTypeSpec.Type.Char:
878                         case BuiltinTypeSpec.Type.Short:
879                         case BuiltinTypeSpec.Type.UShort:
880                                 ig.Emit (OpCodes.Stind_I2);
881                                 return;
882                         case BuiltinTypeSpec.Type.Float:
883                                 ig.Emit (OpCodes.Stind_R4);
884                                 return;
885                         case BuiltinTypeSpec.Type.Double:
886                                 ig.Emit (OpCodes.Stind_R8);
887                                 return;
888                         case BuiltinTypeSpec.Type.Byte:
889                         case BuiltinTypeSpec.Type.SByte:
890                         case BuiltinTypeSpec.Type.Bool:
891                                 ig.Emit (OpCodes.Stind_I1);
892                                 return;
893                         case BuiltinTypeSpec.Type.IntPtr:
894                                 ig.Emit (OpCodes.Stind_I);
895                                 return;
896                         }
897
898                         switch (type.Kind) {
899                         case MemberKind.Struct:
900                         case MemberKind.TypeParameter:
901                                 if (IsAnonymousStoreyMutateRequired)
902                                         type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
903
904                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
905                                 break;
906                         default:
907                                 ig.Emit (OpCodes.Stind_Ref);
908                                 break;
909                         }
910                 }
911
912                 public void EmitThis ()
913                 {
914                         ig.Emit (OpCodes.Ldarg_0);
915                 }
916
917                 public void EmitEpilogue ()
918                 {
919                         if (epilogue_expressions == null)
920                                 return;
921
922                         foreach (var e in epilogue_expressions)
923                                 e.EmitCleanup (this);
924
925                         epilogue_expressions = null;
926                 }
927
928                 /// <summary>
929                 ///   Returns a temporary storage for a variable of type t as 
930                 ///   a local variable in the current body.
931                 /// </summary>
932                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
933                 {
934                         if (temporary_storage != null) {
935                                 object o;
936                                 if (temporary_storage.TryGetValue (t, out o)) {
937                                         if (o is Stack<LocalBuilder>) {
938                                                 var s = (Stack<LocalBuilder>) o;
939                                                 o = s.Count == 0 ? null : s.Pop ();
940                                         } else {
941                                                 temporary_storage.Remove (t);
942                                         }
943                                 }
944                                 if (o != null)
945                                         return (LocalBuilder) o;
946                         }
947                         return DeclareLocal (t, false);
948                 }
949
950                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
951                 {
952                         if (temporary_storage == null) {
953                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
954                                 temporary_storage.Add (t, b);
955                                 return;
956                         }
957                         object o;
958                         
959                         if (!temporary_storage.TryGetValue (t, out o)) {
960                                 temporary_storage.Add (t, b);
961                                 return;
962                         }
963                         var s = o as Stack<LocalBuilder>;
964                         if (s == null) {
965                                 s = new Stack<LocalBuilder> ();
966                                 s.Push ((LocalBuilder)o);
967                                 temporary_storage [t] = s;
968                         }
969                         s.Push (b);
970                 }
971
972                 /// <summary>
973                 ///   ReturnValue creates on demand the LocalBuilder for the
974                 ///   return value from the function.  By default this is not
975                 ///   used.  This is only required when returns are found inside
976                 ///   Try or Catch statements.
977                 ///
978                 ///   This method is typically invoked from the Emit phase, so
979                 ///   we allow the creation of a return label if it was not
980                 ///   requested during the resolution phase.   Could be cleaned
981                 ///   up, but it would replicate a lot of logic in the Emit phase
982                 ///   of the code that uses it.
983                 /// </summary>
984                 public LocalBuilder TemporaryReturn ()
985                 {
986                         if (return_value == null){
987                                 return_value = DeclareLocal (return_type, false);
988                         }
989
990                         return return_value;
991                 }
992         }
993
994         public class ConditionalAccessContext
995         {
996                 public ConditionalAccessContext (TypeSpec type, Label endLabel)
997                 {
998                         Type = type;
999                         EndLabel = endLabel;
1000                 }
1001
1002                 public bool Statement { get; set; }
1003                 public Label EndLabel { get; private set; }
1004                 public TypeSpec Type { get; private set; }
1005         }
1006
1007         struct CallEmitter
1008         {
1009                 public Expression InstanceExpression;
1010
1011                 //
1012                 // When call has to leave an extra copy of all arguments on the stack
1013                 //
1014                 public bool DuplicateArguments;
1015
1016                 //
1017                 // Does not emit InstanceExpression load when InstanceExpressionOnStack
1018                 // is set. Used by compound assignments.
1019                 //
1020                 public bool InstanceExpressionOnStack;
1021
1022                 //
1023                 // Any of arguments contains await expression
1024                 //
1025                 public bool HasAwaitArguments;
1026
1027                 public bool ConditionalAccess;
1028
1029                 //
1030                 // When dealing with await arguments the original arguments are converted
1031                 // into a new set with hoisted stack results
1032                 //
1033                 public Arguments EmittedArguments;
1034
1035                 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
1036                 {
1037                         EmitPredefined (ec, method, Arguments, false, loc);
1038                 }
1039
1040                 public void EmitStatement (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
1041                 {
1042                         EmitPredefined (ec, method, Arguments, true, loc);
1043                 }
1044
1045                 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location? loc = null)
1046                 {
1047                         Expression instance_copy = null;
1048
1049                         if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
1050                                 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
1051                                 if (HasAwaitArguments && InstanceExpressionOnStack) {
1052                                         throw new NotSupportedException ();
1053                                 }
1054                         }
1055
1056                         OpCode call_op;
1057                         LocalTemporary lt = null;
1058
1059                         if (method.IsStatic) {
1060                                 call_op = OpCodes.Call;
1061                         } else {
1062                                 call_op = IsVirtualCallRequired (InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call;
1063
1064                                 if (HasAwaitArguments) {
1065                                         instance_copy = InstanceExpression.EmitToField (ec);
1066                                         var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
1067
1068                                         if (Arguments == null) {
1069                                                 ie.EmitLoad (ec);
1070                                         }
1071                                 } else if (!InstanceExpressionOnStack) {
1072                                         var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType));
1073                                         ie.Emit (ec, ConditionalAccess);
1074
1075                                         if (DuplicateArguments) {
1076                                                 ec.Emit (OpCodes.Dup);
1077                                                 if (Arguments != null && Arguments.Count != 0) {
1078                                                         lt = new LocalTemporary (ie.GetStackType (ec));
1079                                                         lt.Store (ec);
1080                                                         instance_copy = lt;
1081                                                 }
1082                                         }
1083                                 }
1084                         }
1085
1086                         if (Arguments != null && !InstanceExpressionOnStack) {
1087                                 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
1088                                 if (EmittedArguments != null) {
1089                                         if (instance_copy != null) {
1090                                                 var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
1091                                                 ie.Emit (ec, ConditionalAccess);
1092
1093                                                 if (lt != null)
1094                                                         lt.Release (ec);
1095                                         }
1096
1097                                         EmittedArguments.Emit (ec);
1098                                 }
1099                         }
1100
1101                         if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) {
1102                                 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
1103                         }
1104
1105                         if (loc != null) {
1106                                 //
1107                                 // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
1108                                 // break at right place when LHS expression can be stepped-into
1109                                 //
1110                                 ec.MarkCallEntry (loc.Value);
1111                         }
1112
1113                         //
1114                         // Set instance expression to actual result expression. When it contains await it can be
1115                         // picked up by caller
1116                         //
1117                         InstanceExpression = instance_copy;
1118
1119                         if (method.Parameters.HasArglist) {
1120                                 var varargs_types = GetVarargsTypes (method, Arguments);
1121                                 ec.Emit (call_op, method, varargs_types);
1122                         } else {
1123                                 //
1124                                 // If you have:
1125                                 // this.DoFoo ();
1126                                 // and DoFoo is not virtual, you can omit the callvirt,
1127                                 // because you don't need the null checking behavior.
1128                                 //
1129                                 ec.Emit (call_op, method);
1130                         }
1131
1132                         // 
1133                         // Pop the return value if there is one and stack should be empty
1134                         //
1135                         if (statement && method.ReturnType.Kind != MemberKind.Void)
1136                                 ec.Emit (OpCodes.Pop);
1137                 }
1138
1139                 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1140                 {
1141                         AParametersCollection pd = method.Parameters;
1142
1143                         Argument a = arguments[pd.Count - 1];
1144                         Arglist list = (Arglist) a.Expr;
1145
1146                         return list.ArgumentTypes;
1147                 }
1148
1149                 //
1150                 // Used to decide whether call or callvirt is needed
1151                 //
1152                 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1153                 {
1154                         //
1155                         // There are 2 scenarious where we emit callvirt
1156                         //
1157                         // Case 1: A method is virtual and it's not used to call base
1158                         // Case 2: A method instance expression can be null. In this casen callvirt ensures
1159                         // correct NRE exception when the method is called
1160                         //
1161                         var decl_type = method.DeclaringType;
1162                         if (decl_type.IsStruct || decl_type.IsEnum)
1163                                 return false;
1164
1165                         if (instance is BaseThis)
1166                                 return false;
1167
1168                         //
1169                         // It's non-virtual and will never be null and it can be determined
1170                         // whether it's known value or reference type by verifier
1171                         //
1172                         if (!method.IsVirtual && Expression.IsNeverNull (instance) && !instance.Type.IsGenericParameter)
1173                                 return false;
1174
1175                         return true;
1176                 }
1177
1178                 static bool IsAddressCall (Expression instance, OpCode callOpcode, TypeSpec declaringType)
1179                 {
1180                         var instance_type = instance.Type;
1181                         return (instance_type.IsStructOrEnum && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1182                                 instance_type.IsGenericParameter || declaringType.IsNullableType;
1183                 }
1184         }
1185
1186         public struct InstanceEmitter
1187         {
1188                 readonly Expression instance;
1189                 readonly bool addressRequired;
1190
1191                 public InstanceEmitter (Expression instance, bool addressLoad)
1192                 {
1193                         this.instance = instance;
1194                         this.addressRequired = addressLoad;
1195                 }
1196
1197                 public void Emit (EmitContext ec, bool conditionalAccess)
1198                 {
1199                         Label NullOperatorLabel;
1200                         Nullable.Unwrap unwrap;
1201
1202                         if (conditionalAccess && Expression.IsNeverNull (instance))
1203                                 conditionalAccess = false;
1204
1205                         if (conditionalAccess) {
1206                                 NullOperatorLabel = ec.DefineLabel ();
1207                                 unwrap = instance as Nullable.Unwrap;
1208                         } else {
1209                                 NullOperatorLabel = new Label ();
1210                                 unwrap = null;
1211                         }
1212
1213                         IMemoryLocation instance_address = null;
1214                         bool conditional_access_dup = false;
1215
1216                         if (unwrap != null) {
1217                                 unwrap.Store (ec);
1218                                 unwrap.EmitCheck (ec);
1219                                 ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);
1220                         } else {
1221                                 if (conditionalAccess && addressRequired) {
1222                                         //
1223                                         // Don't allocate temp variable when instance load is cheap and load and load-address
1224                                         // operate on same memory
1225                                         //
1226                                         instance_address = instance as VariableReference;
1227                                         if (instance_address == null)
1228                                                 instance_address = instance as LocalTemporary;
1229
1230                                         if (instance_address == null) {
1231                                                 EmitLoad (ec);
1232                                                 ec.Emit (OpCodes.Dup);
1233                                                 ec.EmitLoadFromPtr (instance.Type);
1234
1235                                                 conditional_access_dup = true;
1236                                         } else {
1237                                                 instance.Emit (ec);
1238                                         }
1239
1240                                         if (instance.Type.Kind == MemberKind.TypeParameter)
1241                                                 ec.Emit (OpCodes.Box, instance.Type);
1242                                 } else {
1243                                         EmitLoad (ec);
1244
1245                                         if (conditionalAccess) {
1246                                                 conditional_access_dup = !IsInexpensiveLoad ();
1247                                                 if (conditional_access_dup)
1248                                                         ec.Emit (OpCodes.Dup);
1249                                         }
1250                                 }
1251
1252                                 if (conditionalAccess) {
1253                                         ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);
1254
1255                                         if (conditional_access_dup)
1256                                                 ec.Emit (OpCodes.Pop);
1257                                 }
1258                         }
1259
1260                         if (conditionalAccess) {
1261                                 if (!ec.ConditionalAccess.Statement) {
1262                                         if (ec.ConditionalAccess.Type.IsNullableType)
1263                                                 Nullable.LiftedNull.Create (ec.ConditionalAccess.Type, Location.Null).Emit (ec);
1264                                         else
1265                                                 ec.EmitNull ();
1266                                 }
1267
1268                                 ec.Emit (OpCodes.Br, ec.ConditionalAccess.EndLabel);
1269                                 ec.MarkLabel (NullOperatorLabel);
1270
1271                                 if (instance_address != null) {
1272                                         instance_address.AddressOf (ec, AddressOp.Load);
1273                                 } else if (unwrap != null) {
1274                                         unwrap.Emit (ec);
1275                                         var tmp = ec.GetTemporaryLocal (unwrap.Type);
1276                                         ec.Emit (OpCodes.Stloc, tmp);
1277                                         ec.Emit (OpCodes.Ldloca, tmp);
1278                                         ec.FreeTemporaryLocal (tmp, unwrap.Type);
1279                                 } else if (!conditional_access_dup) {
1280                                         instance.Emit (ec);
1281                                 }
1282                         }
1283                 }
1284
1285                 public void EmitLoad (EmitContext ec)
1286                 {
1287                         var instance_type = instance.Type;
1288
1289                         //
1290                         // Push the instance expression
1291                         //
1292                         if (addressRequired) {
1293                                 //
1294                                 // If the expression implements IMemoryLocation, then
1295                                 // we can optimize and use AddressOf on the
1296                                 // return.
1297                                 //
1298                                 // If not we have to use some temporary storage for
1299                                 // it.
1300                                 var iml = instance as IMemoryLocation;
1301                                 if (iml != null) {
1302                                         iml.AddressOf (ec, AddressOp.Load);
1303                                 } else {
1304                                         LocalTemporary temp = new LocalTemporary (instance_type);
1305                                         instance.Emit (ec);
1306                                         temp.Store (ec);
1307                                         temp.AddressOf (ec, AddressOp.Load);
1308                                 }
1309
1310                                 return;
1311                         }
1312
1313                         instance.Emit (ec);
1314
1315                         // Only to make verifier happy
1316                         if (RequiresBoxing ())
1317                                 ec.Emit (OpCodes.Box, instance_type);
1318                 }
1319
1320                 public TypeSpec GetStackType (EmitContext ec)
1321                 {
1322                         var instance_type = instance.Type;
1323
1324                         if (addressRequired)
1325                                 return ReferenceContainer.MakeType (ec.Module, instance_type);
1326
1327                         if (instance_type.IsStructOrEnum)
1328                                 return ec.Module.Compiler.BuiltinTypes.Object;
1329
1330                         return instance_type;
1331                 }
1332
1333                 bool RequiresBoxing ()
1334                 {
1335                         var instance_type = instance.Type;
1336                         if (instance_type.IsGenericParameter && !(instance is This) && TypeSpec.IsReferenceType (instance_type))
1337                                 return true;
1338
1339                         if (instance_type.IsStructOrEnum)
1340                                 return true;
1341
1342                         return false;
1343                 }
1344
1345                 bool IsInexpensiveLoad ()
1346                 {
1347                         if (instance is Constant)
1348                                 return instance.IsSideEffectFree;
1349
1350                         if (RequiresBoxing ())
1351                                 return false;
1352
1353                         var vr = instance as VariableReference;
1354                         if (vr != null)
1355                                 return !vr.IsRef;
1356
1357                         if (instance is LocalTemporary)
1358                                 return true;
1359
1360                         var fe = instance as FieldExpr;
1361                         if (fe != null)
1362                                 return fe.IsStatic || fe.InstanceExpression is This;
1363
1364                         return false;
1365                 }
1366         }
1367 }