[jit] Fix the saving of the 'cfg->ret_var_set' flag when inlining, it was set to...
[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                         methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
266                         return true;
267                 }
268
269                 public void MarkCallEntry (Location loc)
270                 {
271                         if (!EmitAccurateDebugInfo)
272                                 return;
273
274                         //
275                         // TODO: This should emit different kind of sequence point to make
276                         // step-over work for statement over multiple lines
277                         //
278                         // Debugging experience for Foo (A () + B ()) where A and B are
279                         // on separate lines is not great
280                         //
281                         Mark (loc);
282                 }
283
284                 public void DefineLocalVariable (string name, LocalBuilder builder)
285                 {
286                         if ((flags & Options.OmitDebugInfo) != 0)
287                                 return;
288
289                         methodSymbols.AddLocal (builder.LocalIndex, name);
290                 }
291
292                 public void BeginCatchBlock (TypeSpec type)
293                 {
294                         if (IsAnonymousStoreyMutateRequired)
295                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
296
297                         ig.BeginCatchBlock (type.GetMetaInfo ());
298                 }
299
300                 public void BeginFilterHandler ()
301                 {
302                         ig.BeginCatchBlock (null);
303                 }
304
305                 public void BeginExceptionBlock ()
306                 {
307                         ig.BeginExceptionBlock ();
308                 }
309
310                 public void BeginExceptionFilterBlock ()
311                 {
312                         ig.BeginExceptFilterBlock ();
313                 }
314
315                 public void BeginFinallyBlock ()
316                 {
317                         ig.BeginFinallyBlock ();
318                 }
319
320                 public void BeginScope (int scopeIndex)
321                 {
322                         if ((flags & Options.OmitDebugInfo) != 0)
323                                 return;
324
325                         methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset, scopeIndex);
326                 }
327
328                 public void BeginCompilerScope (int scopeIndex)
329                 {
330                         if ((flags & Options.OmitDebugInfo) != 0)
331                                 return;
332
333                         methodSymbols.StartBlock (CodeBlockEntry.Type.CompilerGenerated, ig.ILOffset, scopeIndex);
334                 }
335
336                 public void EndExceptionBlock ()
337                 {
338                         ig.EndExceptionBlock ();
339                 }
340
341                 public void EndScope ()
342                 {
343                         if ((flags & Options.OmitDebugInfo) != 0)
344                                 return;
345
346                         methodSymbols.EndBlock (ig.ILOffset);
347                 }
348
349                 public void CloseConditionalAccess (TypeSpec type)
350                 {
351                         if (type != null)
352                                 Emit (OpCodes.Newobj, Nullable.NullableInfo.GetConstructor (type));
353
354                         MarkLabel (ConditionalAccess.EndLabel);
355                         ConditionalAccess = null;
356                 }
357
358                 //
359                 // Creates a nested container in this context for all dynamic compiler generated stuff
360                 //
361                 internal DynamicSiteClass CreateDynamicSite ()
362                 {
363                         if (dynamic_site_container == null) {
364                                 var mc = member_context.CurrentMemberDefinition as MemberBase;
365                                 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
366
367                                 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
368                                 dynamic_site_container.CreateContainer ();
369                                 dynamic_site_container.DefineContainer ();
370                                 dynamic_site_container.Define ();
371
372                                 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
373                                 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
374                                 CurrentType.MemberCache.AddMember (inflated);
375                         }
376
377                         return dynamic_site_container;
378                 }
379
380                 public Label CreateReturnLabel ()
381                 {
382                         if (!return_label.HasValue)
383                                 return_label = DefineLabel ();
384
385                         return return_label.Value;
386                 }
387
388                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
389                 {
390                         if (IsAnonymousStoreyMutateRequired)
391                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
392
393                         if (pinned) {
394                                 //
395                                 // This is for .net compatibility. I am not sure why pinned
396                                 // pointer temps are converted to & even if they are pointers to
397                                 // pointers.
398                                 //
399                                 var pt = type as PointerContainer;
400                                 if (pt != null) {
401                                         type = pt.Element;
402                                         if (type.Kind == MemberKind.Void)
403                                                 type = Module.Compiler.BuiltinTypes.IntPtr;
404                                         
405                                         return ig.DeclareLocal (type.GetMetaInfo ().MakeByRefType (), true);
406                                 }
407                         }
408
409                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
410                 }
411
412                 public Label DefineLabel ()
413                 {
414                         return ig.DefineLabel ();
415                 }
416
417                 //
418                 // Creates temporary field in current async storey
419                 //
420                 public StackFieldExpr GetTemporaryField (TypeSpec type, bool initializedFieldRequired = false)
421                 {
422                         var f = AsyncTaskStorey.AddCapturedLocalVariable (type, initializedFieldRequired);
423                         var fexpr = new StackFieldExpr (f);
424                         fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
425                         return fexpr;
426                 }
427
428                 public void MarkLabel (Label label)
429                 {
430                         ig.MarkLabel (label);
431                 }
432
433                 public void Emit (OpCode opcode)
434                 {
435                         ig.Emit (opcode);
436                 }
437
438                 public void Emit (OpCode opcode, LocalBuilder local)
439                 {
440                         ig.Emit (opcode, local);
441                 }
442
443                 public void Emit (OpCode opcode, string arg)
444                 {
445                         ig.Emit (opcode, arg);
446                 }
447
448                 public void Emit (OpCode opcode, double arg)
449                 {
450                         ig.Emit (opcode, arg);
451                 }
452
453                 public void Emit (OpCode opcode, float arg)
454                 {
455                         ig.Emit (opcode, arg);
456                 }
457
458                 public void Emit (OpCode opcode, Label label)
459                 {
460                         ig.Emit (opcode, label);
461                 }
462
463                 public void Emit (OpCode opcode, Label[] labels)
464                 {
465                         ig.Emit (opcode, labels);
466                 }
467
468                 public void Emit (OpCode opcode, TypeSpec type)
469                 {
470                         if (IsAnonymousStoreyMutateRequired)
471                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
472
473                         ig.Emit (opcode, type.GetMetaInfo ());
474                 }
475
476                 public void Emit (OpCode opcode, FieldSpec field)
477                 {
478                         if (IsAnonymousStoreyMutateRequired)
479                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
480
481                         ig.Emit (opcode, field.GetMetaInfo ());
482                 }
483
484                 public void Emit (OpCode opcode, MethodSpec method)
485                 {
486                         if (IsAnonymousStoreyMutateRequired)
487                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
488
489                         if (method.IsConstructor)
490                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
491                         else
492                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
493                 }
494
495                 // TODO: REMOVE breaks mutator
496                 public void Emit (OpCode opcode, MethodInfo method)
497                 {
498                         ig.Emit (opcode, method);
499                 }
500
501                 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
502                 {
503                         // TODO MemberCache: This should mutate too
504                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
505                 }
506
507                 public void EmitArrayNew (ArrayContainer ac)
508                 {
509                         if (ac.Rank == 1) {
510                                 var type = IsAnonymousStoreyMutateRequired ?
511                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
512                                         ac.Element;
513
514                                 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
515                         } else {
516                                 if (IsAnonymousStoreyMutateRequired)
517                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
518
519                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
520                         }
521                 }
522
523                 public void EmitArrayAddress (ArrayContainer ac)
524                 {
525                         if (ac.Rank > 1) {
526                                 if (IsAnonymousStoreyMutateRequired)
527                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
528
529                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
530                         } else {
531                                 var type = IsAnonymousStoreyMutateRequired ?
532                                         CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
533                                         ac.Element;
534
535                                 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
536                         }
537                 }
538
539                 //
540                 // Emits the right opcode to load from an array
541                 //
542                 public void EmitArrayLoad (ArrayContainer ac)
543                 {
544                         if (ac.Rank > 1) {
545                                 if (IsAnonymousStoreyMutateRequired)
546                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
547
548                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
549                                 return;
550                         }
551
552
553                         var type = ac.Element;
554                         if (type.Kind == MemberKind.Enum)
555                                 type = EnumSpec.GetUnderlyingType (type);
556
557                         switch (type.BuiltinType) {
558                         case BuiltinTypeSpec.Type.Bool:
559                                 //
560                                 // bool array can actually store any byte value in underlying byte slot
561                                 // and C# spec does not specify any normalization rule, except the result
562                                 // is undefined
563                                 //
564                         case BuiltinTypeSpec.Type.Byte:
565                                 ig.Emit (OpCodes.Ldelem_U1);
566                                 break;
567                         case BuiltinTypeSpec.Type.SByte:
568                                 ig.Emit (OpCodes.Ldelem_I1);
569                                 break;
570                         case BuiltinTypeSpec.Type.Short:
571                                 ig.Emit (OpCodes.Ldelem_I2);
572                                 break;
573                         case BuiltinTypeSpec.Type.UShort:
574                         case BuiltinTypeSpec.Type.Char:
575                                 ig.Emit (OpCodes.Ldelem_U2);
576                                 break;
577                         case BuiltinTypeSpec.Type.Int:
578                                 ig.Emit (OpCodes.Ldelem_I4);
579                                 break;
580                         case BuiltinTypeSpec.Type.UInt:
581                                 ig.Emit (OpCodes.Ldelem_U4);
582                                 break;
583                         case BuiltinTypeSpec.Type.ULong:
584                         case BuiltinTypeSpec.Type.Long:
585                                 ig.Emit (OpCodes.Ldelem_I8);
586                                 break;
587                         case BuiltinTypeSpec.Type.Float:
588                                 ig.Emit (OpCodes.Ldelem_R4);
589                                 break;
590                         case BuiltinTypeSpec.Type.Double:
591                                 ig.Emit (OpCodes.Ldelem_R8);
592                                 break;
593                         case BuiltinTypeSpec.Type.IntPtr:
594                                 ig.Emit (OpCodes.Ldelem_I);
595                                 break;
596                         default:
597                                 switch (type.Kind) {
598                                 case MemberKind.Struct:
599                                         if (IsAnonymousStoreyMutateRequired)
600                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
601
602                                         ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
603                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
604                                         break;
605                                 case MemberKind.TypeParameter:
606                                         if (IsAnonymousStoreyMutateRequired)
607                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
608
609                                         ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
610                                         break;
611                                 case MemberKind.PointerType:
612                                         ig.Emit (OpCodes.Ldelem_I);
613                                         break;
614                                 default:
615                                         ig.Emit (OpCodes.Ldelem_Ref);
616                                         break;
617                                 }
618                                 break;
619                         }
620                 }
621
622                 //
623                 // Emits the right opcode to store to an array
624                 //
625                 public void EmitArrayStore (ArrayContainer ac)
626                 {
627                         if (ac.Rank > 1) {
628                                 if (IsAnonymousStoreyMutateRequired)
629                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
630
631                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
632                                 return;
633                         }
634
635                         var type = ac.Element;
636
637                         if (type.Kind == MemberKind.Enum)
638                                 type = EnumSpec.GetUnderlyingType (type);
639
640                         switch (type.BuiltinType) {
641                         case BuiltinTypeSpec.Type.Byte:
642                         case BuiltinTypeSpec.Type.SByte:
643                         case BuiltinTypeSpec.Type.Bool:
644                                 Emit (OpCodes.Stelem_I1);
645                                 return;
646                         case BuiltinTypeSpec.Type.Short:
647                         case BuiltinTypeSpec.Type.UShort:
648                         case BuiltinTypeSpec.Type.Char:
649                                 Emit (OpCodes.Stelem_I2);
650                                 return;
651                         case BuiltinTypeSpec.Type.Int:
652                         case BuiltinTypeSpec.Type.UInt:
653                                 Emit (OpCodes.Stelem_I4);
654                                 return;
655                         case BuiltinTypeSpec.Type.Long:
656                         case BuiltinTypeSpec.Type.ULong:
657                                 Emit (OpCodes.Stelem_I8);
658                                 return;
659                         case BuiltinTypeSpec.Type.Float:
660                                 Emit (OpCodes.Stelem_R4);
661                                 return;
662                         case BuiltinTypeSpec.Type.Double:
663                                 Emit (OpCodes.Stelem_R8);
664                                 return;
665                         }
666
667                         switch (type.Kind) {
668                         case MemberKind.Struct:
669                                 Emit (OpCodes.Stobj, type);
670                                 break;
671                         case MemberKind.TypeParameter:
672                                 Emit (OpCodes.Stelem, type);
673                                 break;
674                         case MemberKind.PointerType:
675                                 Emit (OpCodes.Stelem_I);
676                                 break;
677                         default:
678                                 Emit (OpCodes.Stelem_Ref);
679                                 break;
680                         }
681                 }
682
683                 public void EmitInt (int i)
684                 {
685                         EmitIntConstant (i);
686                 }
687
688                 void EmitIntConstant (int i)
689                 {
690                         switch (i) {
691                         case -1:
692                                 ig.Emit (OpCodes.Ldc_I4_M1);
693                                 break;
694
695                         case 0:
696                                 ig.Emit (OpCodes.Ldc_I4_0);
697                                 break;
698
699                         case 1:
700                                 ig.Emit (OpCodes.Ldc_I4_1);
701                                 break;
702
703                         case 2:
704                                 ig.Emit (OpCodes.Ldc_I4_2);
705                                 break;
706
707                         case 3:
708                                 ig.Emit (OpCodes.Ldc_I4_3);
709                                 break;
710
711                         case 4:
712                                 ig.Emit (OpCodes.Ldc_I4_4);
713                                 break;
714
715                         case 5:
716                                 ig.Emit (OpCodes.Ldc_I4_5);
717                                 break;
718
719                         case 6:
720                                 ig.Emit (OpCodes.Ldc_I4_6);
721                                 break;
722
723                         case 7:
724                                 ig.Emit (OpCodes.Ldc_I4_7);
725                                 break;
726
727                         case 8:
728                                 ig.Emit (OpCodes.Ldc_I4_8);
729                                 break;
730
731                         default:
732                                 if (i >= -128 && i <= 127) {
733                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
734                                 } else
735                                         ig.Emit (OpCodes.Ldc_I4, i);
736                                 break;
737                         }
738                 }
739
740                 public void EmitLong (long l)
741                 {
742                         if (l >= int.MinValue && l <= int.MaxValue) {
743                                 EmitIntConstant (unchecked ((int) l));
744                                 ig.Emit (OpCodes.Conv_I8);
745                         } else if (l >= 0 && l <= uint.MaxValue) {
746                                 EmitIntConstant (unchecked ((int) l));
747                                 ig.Emit (OpCodes.Conv_U8);
748                         } else {
749                                 ig.Emit (OpCodes.Ldc_I8, l);
750                         }
751                 }
752
753                 //
754                 // Load the object from the pointer.  
755                 //
756                 public void EmitLoadFromPtr (TypeSpec type)
757                 {
758                         if (type.Kind == MemberKind.Enum)
759                                 type = EnumSpec.GetUnderlyingType (type);
760
761                         switch (type.BuiltinType) {
762                         case BuiltinTypeSpec.Type.Int:
763                                 ig.Emit (OpCodes.Ldind_I4);
764                                 break;
765                         case BuiltinTypeSpec.Type.UInt:
766                                 ig.Emit (OpCodes.Ldind_U4);
767                                 break;
768                         case BuiltinTypeSpec.Type.Short:
769                                 ig.Emit (OpCodes.Ldind_I2);
770                                 break;
771                         case BuiltinTypeSpec.Type.UShort:
772                         case BuiltinTypeSpec.Type.Char:
773                                 ig.Emit (OpCodes.Ldind_U2);
774                                 break;
775                         case BuiltinTypeSpec.Type.Byte:
776                                 ig.Emit (OpCodes.Ldind_U1);
777                                 break;
778                         case BuiltinTypeSpec.Type.SByte:
779                         case BuiltinTypeSpec.Type.Bool:
780                                 ig.Emit (OpCodes.Ldind_I1);
781                                 break;
782                         case BuiltinTypeSpec.Type.ULong:
783                         case BuiltinTypeSpec.Type.Long:
784                                 ig.Emit (OpCodes.Ldind_I8);
785                                 break;
786                         case BuiltinTypeSpec.Type.Float:
787                                 ig.Emit (OpCodes.Ldind_R4);
788                                 break;
789                         case BuiltinTypeSpec.Type.Double:
790                                 ig.Emit (OpCodes.Ldind_R8);
791                                 break;
792                         case BuiltinTypeSpec.Type.IntPtr:
793                                 ig.Emit (OpCodes.Ldind_I);
794                                 break;
795                         default:
796                                 switch (type.Kind) {
797                                 case MemberKind.Struct:
798                                 case MemberKind.TypeParameter:
799                                         if (IsAnonymousStoreyMutateRequired)
800                                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
801
802                                         ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
803                                         break;
804                                 case MemberKind.PointerType:
805                                         ig.Emit (OpCodes.Ldind_I);
806                                         break;
807                                 default:
808                                         ig.Emit (OpCodes.Ldind_Ref);
809                                         break;
810                                 }
811                                 break;
812                         }
813                 }
814
815                 public void EmitNull ()
816                 {
817                         ig.Emit (OpCodes.Ldnull);
818                 }
819
820                 public void EmitArgumentAddress (int pos)
821                 {
822                         if (!IsStatic)
823                                 ++pos;
824
825                         if (pos > byte.MaxValue)
826                                 ig.Emit (OpCodes.Ldarga, pos);
827                         else
828                                 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
829                 }
830
831                 public void EmitArgumentLoad (int pos)
832                 {
833                         if (!IsStatic)
834                                 ++pos;
835
836                         switch (pos) {
837                         case 0: ig.Emit (OpCodes.Ldarg_0); break;
838                         case 1: ig.Emit (OpCodes.Ldarg_1); break;
839                         case 2: ig.Emit (OpCodes.Ldarg_2); break;
840                         case 3: ig.Emit (OpCodes.Ldarg_3); break;
841                         default:
842                                 if (pos > byte.MaxValue)
843                                         ig.Emit (OpCodes.Ldarg, pos);
844                                 else
845                                         ig.Emit (OpCodes.Ldarg_S, (byte) pos);
846                                 break;
847                         }
848                 }
849
850                 public void EmitArgumentStore (int pos)
851                 {
852                         if (!IsStatic)
853                                 ++pos;
854
855                         if (pos > byte.MaxValue)
856                                 ig.Emit (OpCodes.Starg, pos);
857                         else
858                                 ig.Emit (OpCodes.Starg_S, (byte) pos);
859                 }
860
861                 //
862                 // The stack contains the pointer and the value of type `type'
863                 //
864                 public void EmitStoreFromPtr (TypeSpec type)
865                 {
866                         if (type.IsEnum)
867                                 type = EnumSpec.GetUnderlyingType (type);
868
869                         switch (type.BuiltinType) {
870                         case BuiltinTypeSpec.Type.Int:
871                         case BuiltinTypeSpec.Type.UInt:
872                                 ig.Emit (OpCodes.Stind_I4);
873                                 return;
874                         case BuiltinTypeSpec.Type.Long:
875                         case BuiltinTypeSpec.Type.ULong:
876                                 ig.Emit (OpCodes.Stind_I8);
877                                 return;
878                         case BuiltinTypeSpec.Type.Char:
879                         case BuiltinTypeSpec.Type.Short:
880                         case BuiltinTypeSpec.Type.UShort:
881                                 ig.Emit (OpCodes.Stind_I2);
882                                 return;
883                         case BuiltinTypeSpec.Type.Float:
884                                 ig.Emit (OpCodes.Stind_R4);
885                                 return;
886                         case BuiltinTypeSpec.Type.Double:
887                                 ig.Emit (OpCodes.Stind_R8);
888                                 return;
889                         case BuiltinTypeSpec.Type.Byte:
890                         case BuiltinTypeSpec.Type.SByte:
891                         case BuiltinTypeSpec.Type.Bool:
892                                 ig.Emit (OpCodes.Stind_I1);
893                                 return;
894                         case BuiltinTypeSpec.Type.IntPtr:
895                                 ig.Emit (OpCodes.Stind_I);
896                                 return;
897                         }
898
899                         switch (type.Kind) {
900                         case MemberKind.Struct:
901                         case MemberKind.TypeParameter:
902                                 if (IsAnonymousStoreyMutateRequired)
903                                         type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
904
905                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
906                                 break;
907                         case MemberKind.PointerType:
908                                 ig.Emit (OpCodes.Stind_I);
909                                 break;
910                         default:
911                                 ig.Emit (OpCodes.Stind_Ref);
912                                 break;
913                         }
914                 }
915
916                 public void EmitThis ()
917                 {
918                         ig.Emit (OpCodes.Ldarg_0);
919                 }
920
921                 public void EmitEpilogue ()
922                 {
923                         if (epilogue_expressions == null)
924                                 return;
925
926                         foreach (var e in epilogue_expressions)
927                                 e.EmitCleanup (this);
928
929                         epilogue_expressions = null;
930                 }
931
932                 /// <summary>
933                 ///   Returns a temporary storage for a variable of type t as 
934                 ///   a local variable in the current body.
935                 /// </summary>
936                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
937                 {
938                         if (temporary_storage != null) {
939                                 object o;
940                                 if (temporary_storage.TryGetValue (t, out o)) {
941                                         if (o is Stack<LocalBuilder>) {
942                                                 var s = (Stack<LocalBuilder>) o;
943                                                 o = s.Count == 0 ? null : s.Pop ();
944                                         } else {
945                                                 temporary_storage.Remove (t);
946                                         }
947                                 }
948                                 if (o != null)
949                                         return (LocalBuilder) o;
950                         }
951                         return DeclareLocal (t, false);
952                 }
953
954                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
955                 {
956                         if (temporary_storage == null) {
957                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
958                                 temporary_storage.Add (t, b);
959                                 return;
960                         }
961                         object o;
962                         
963                         if (!temporary_storage.TryGetValue (t, out o)) {
964                                 temporary_storage.Add (t, b);
965                                 return;
966                         }
967                         var s = o as Stack<LocalBuilder>;
968                         if (s == null) {
969                                 s = new Stack<LocalBuilder> ();
970                                 s.Push ((LocalBuilder)o);
971                                 temporary_storage [t] = s;
972                         }
973                         s.Push (b);
974                 }
975
976                 /// <summary>
977                 ///   ReturnValue creates on demand the LocalBuilder for the
978                 ///   return value from the function.  By default this is not
979                 ///   used.  This is only required when returns are found inside
980                 ///   Try or Catch statements.
981                 ///
982                 ///   This method is typically invoked from the Emit phase, so
983                 ///   we allow the creation of a return label if it was not
984                 ///   requested during the resolution phase.   Could be cleaned
985                 ///   up, but it would replicate a lot of logic in the Emit phase
986                 ///   of the code that uses it.
987                 /// </summary>
988                 public LocalBuilder TemporaryReturn ()
989                 {
990                         if (return_value == null){
991                                 return_value = DeclareLocal (return_type, false);
992                         }
993
994                         return return_value;
995                 }
996         }
997
998         public class ConditionalAccessContext
999         {
1000                 public ConditionalAccessContext (TypeSpec type, Label endLabel)
1001                 {
1002                         Type = type;
1003                         EndLabel = endLabel;
1004                 }
1005
1006                 public bool Statement { get; set; }
1007                 public Label EndLabel { get; private set; }
1008                 public TypeSpec Type { get; private set; }
1009         }
1010
1011         struct CallEmitter
1012         {
1013                 public Expression InstanceExpression;
1014
1015                 //
1016                 // When call has to leave an extra copy of all arguments on the stack
1017                 //
1018                 public bool DuplicateArguments;
1019
1020                 //
1021                 // Does not emit InstanceExpression load when InstanceExpressionOnStack
1022                 // is set. Used by compound assignments.
1023                 //
1024                 public bool InstanceExpressionOnStack;
1025
1026                 //
1027                 // Any of arguments contains await expression
1028                 //
1029                 public bool HasAwaitArguments;
1030
1031                 public bool ConditionalAccess;
1032
1033                 //
1034                 // When dealing with await arguments the original arguments are converted
1035                 // into a new set with hoisted stack results
1036                 //
1037                 public Arguments EmittedArguments;
1038
1039                 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
1040                 {
1041                         EmitPredefined (ec, method, Arguments, false, loc);
1042                 }
1043
1044                 public void EmitStatement (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
1045                 {
1046                         EmitPredefined (ec, method, Arguments, true, loc);
1047                 }
1048
1049                 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location? loc = null)
1050                 {
1051                         Expression instance_copy = null;
1052
1053                         if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
1054                                 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
1055                                 if (HasAwaitArguments && InstanceExpressionOnStack) {
1056                                         throw new NotSupportedException ();
1057                                 }
1058                         }
1059
1060                         OpCode call_op;
1061                         LocalTemporary lt = null;
1062
1063                         if (method.IsStatic) {
1064                                 call_op = OpCodes.Call;
1065                         } else {
1066                                 call_op = IsVirtualCallRequired (InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call;
1067
1068                                 if (HasAwaitArguments) {
1069                                         instance_copy = InstanceExpression.EmitToField (ec);
1070                                         var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
1071
1072                                         if (Arguments == null) {
1073                                                 if (ConditionalAccess)
1074                                                         ie.Emit (ec, true);
1075                                                 else
1076                                                         ie.EmitLoad (ec, true);
1077                                         }
1078                                 } else if (!InstanceExpressionOnStack) {
1079                                         var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType));
1080                                         ie.Emit (ec, ConditionalAccess);
1081
1082                                         if (DuplicateArguments) {
1083                                                 ec.Emit (OpCodes.Dup);
1084                                                 if (Arguments != null && Arguments.Count != 0) {
1085                                                         lt = new LocalTemporary (ie.GetStackType (ec));
1086                                                         lt.Store (ec);
1087                                                         instance_copy = lt;
1088                                                 }
1089                                         }
1090                                 }
1091                         }
1092
1093                         if (Arguments != null && !InstanceExpressionOnStack) {
1094                                 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
1095                                 if (EmittedArguments != null) {
1096                                         if (instance_copy != null) {
1097                                                 var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
1098                                                 ie.Emit (ec, ConditionalAccess);
1099
1100                                                 if (lt != null)
1101                                                         lt.Release (ec);
1102                                         }
1103
1104                                         EmittedArguments.Emit (ec);
1105                                 }
1106                         }
1107
1108                         if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) {
1109                                 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
1110                         }
1111
1112                         if (loc != null) {
1113                                 //
1114                                 // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
1115                                 // break at right place when LHS expression can be stepped-into
1116                                 //
1117                                 ec.MarkCallEntry (loc.Value);
1118                         }
1119
1120                         //
1121                         // Set instance expression to actual result expression. When it contains await it can be
1122                         // picked up by caller
1123                         //
1124                         InstanceExpression = instance_copy;
1125
1126                         if (method.Parameters.HasArglist) {
1127                                 var varargs_types = GetVarargsTypes (method, Arguments);
1128                                 ec.Emit (call_op, method, varargs_types);
1129                         } else {
1130                                 //
1131                                 // If you have:
1132                                 // this.DoFoo ();
1133                                 // and DoFoo is not virtual, you can omit the callvirt,
1134                                 // because you don't need the null checking behavior.
1135                                 //
1136                                 ec.Emit (call_op, method);
1137                         }
1138
1139                         // 
1140                         // Pop the return value if there is one and stack should be empty
1141                         //
1142                         if (statement && method.ReturnType.Kind != MemberKind.Void)
1143                                 ec.Emit (OpCodes.Pop);
1144                 }
1145
1146                 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1147                 {
1148                         AParametersCollection pd = method.Parameters;
1149
1150                         Argument a = arguments[pd.Count - 1];
1151                         Arglist list = (Arglist) a.Expr;
1152
1153                         return list.ArgumentTypes;
1154                 }
1155
1156                 //
1157                 // Used to decide whether call or callvirt is needed
1158                 //
1159                 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1160                 {
1161                         //
1162                         // There are 2 scenarious where we emit callvirt
1163                         //
1164                         // Case 1: A method is virtual and it's not used to call base
1165                         // Case 2: A method instance expression can be null. In this casen callvirt ensures
1166                         // correct NRE exception when the method is called
1167                         //
1168                         var decl_type = method.DeclaringType;
1169                         if (decl_type.IsStruct || decl_type.IsEnum)
1170                                 return false;
1171
1172                         if (instance is BaseThis)
1173                                 return false;
1174
1175                         //
1176                         // It's non-virtual and will never be null and it can be determined
1177                         // whether it's known value or reference type by verifier
1178                         //
1179                         if (!method.IsVirtual && Expression.IsNeverNull (instance) && !instance.Type.IsGenericParameter)
1180                                 return false;
1181
1182                         return true;
1183                 }
1184
1185                 static bool IsAddressCall (Expression instance, OpCode callOpcode, TypeSpec declaringType)
1186                 {
1187                         var instance_type = instance.Type;
1188                         return (instance_type.IsStructOrEnum && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1189                                 instance_type.IsGenericParameter || declaringType.IsNullableType;
1190                 }
1191         }
1192
1193         public struct InstanceEmitter
1194         {
1195                 readonly Expression instance;
1196                 readonly bool addressRequired;
1197
1198                 public InstanceEmitter (Expression instance, bool addressLoad)
1199                 {
1200                         this.instance = instance;
1201                         this.addressRequired = addressLoad;
1202                 }
1203
1204                 public void Emit (EmitContext ec, bool conditionalAccess)
1205                 {
1206                         Label NullOperatorLabel;
1207                         Nullable.Unwrap unwrap;
1208
1209                         if (conditionalAccess && Expression.IsNeverNull (instance))
1210                                 conditionalAccess = false;
1211
1212                         if (conditionalAccess) {
1213                                 NullOperatorLabel = ec.DefineLabel ();
1214                                 unwrap = instance as Nullable.Unwrap;
1215                         } else {
1216                                 NullOperatorLabel = new Label ();
1217                                 unwrap = null;
1218                         }
1219
1220                         IMemoryLocation instance_address = null;
1221                         bool conditional_access_dup = false;
1222
1223                         if (unwrap != null) {
1224                                 unwrap.Store (ec);
1225                                 unwrap.EmitCheck (ec);
1226                                 ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);
1227                         } else {
1228                                 if (conditionalAccess && addressRequired) {
1229                                         //
1230                                         // Don't allocate temp variable when instance load is cheap and load and load-address
1231                                         // operate on same memory
1232                                         //
1233                                         instance_address = instance as VariableReference;
1234                                         if (instance_address == null)
1235                                                 instance_address = instance as LocalTemporary;
1236
1237                                         if (instance_address == null) {
1238                                                 EmitLoad (ec, false);
1239                                                 ec.Emit (OpCodes.Dup);
1240                                                 ec.EmitLoadFromPtr (instance.Type);
1241
1242                                                 conditional_access_dup = true;
1243                                         } else {
1244                                                 instance.Emit (ec);
1245                                         }
1246                                 } else {
1247                                         EmitLoad (ec, !conditionalAccess);
1248
1249                                         if (conditionalAccess) {
1250                                                 conditional_access_dup = !ExpressionAnalyzer.IsInexpensiveLoad (instance);
1251                                                 if (conditional_access_dup)
1252                                                         ec.Emit (OpCodes.Dup);
1253                                         }
1254                                 }
1255
1256                                 if (conditionalAccess) {
1257                                         if (instance.Type.Kind == MemberKind.TypeParameter)
1258                                                 ec.Emit (OpCodes.Box, instance.Type);
1259
1260                                         ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);
1261
1262                                         if (conditional_access_dup)
1263                                                 ec.Emit (OpCodes.Pop);
1264                                 }
1265                         }
1266
1267                         if (conditionalAccess) {
1268                                 if (!ec.ConditionalAccess.Statement) {
1269                                         var t = ec.ConditionalAccess.Type;
1270                                         if (t.IsNullableType)
1271                                                 Nullable.LiftedNull.Create (t, Location.Null).Emit (ec);
1272                                         else {
1273                                                 ec.EmitNull ();
1274
1275                                                 if (t.IsGenericParameter)
1276                                                         ec.Emit (OpCodes.Unbox_Any, t);
1277                                         }
1278                                 }
1279
1280                                 ec.Emit (OpCodes.Br, ec.ConditionalAccess.EndLabel);
1281                                 ec.MarkLabel (NullOperatorLabel);
1282
1283                                 if (instance_address != null) {
1284                                         instance_address.AddressOf (ec, AddressOp.Load);
1285                                 } else if (unwrap != null) {
1286                                         unwrap.Emit (ec);
1287                                         if (addressRequired) {
1288                                                 var tmp = ec.GetTemporaryLocal (unwrap.Type);
1289                                                 ec.Emit (OpCodes.Stloc, tmp);
1290                                                 ec.Emit (OpCodes.Ldloca, tmp);
1291                                                 ec.FreeTemporaryLocal (tmp, unwrap.Type);
1292                                         }
1293                                 } else if (!conditional_access_dup) {
1294                                         instance.Emit (ec);
1295                                 }
1296                         }
1297                 }
1298
1299                 public void EmitLoad (EmitContext ec, bool boxInstance)
1300                 {
1301                         var instance_type = instance.Type;
1302
1303                         //
1304                         // Push the instance expression
1305                         //
1306                         if (addressRequired) {
1307                                 //
1308                                 // If the expression implements IMemoryLocation, then
1309                                 // we can optimize and use AddressOf on the
1310                                 // return.
1311                                 //
1312                                 // If not we have to use some temporary storage for
1313                                 // it.
1314                                 var iml = instance as IMemoryLocation;
1315                                 if (iml != null) {
1316                                         iml.AddressOf (ec, AddressOp.Load);
1317                                 } else {
1318                                         LocalTemporary temp = new LocalTemporary (instance_type);
1319                                         instance.Emit (ec);
1320                                         temp.Store (ec);
1321                                         temp.AddressOf (ec, AddressOp.Load);
1322                                 }
1323
1324                                 return;
1325                         }
1326
1327                         instance.Emit (ec);
1328
1329                         // Only to make verifier happy
1330                         if (boxInstance && ExpressionAnalyzer.RequiresBoxing (instance)) {
1331                                 ec.Emit (OpCodes.Box, instance_type);
1332                         }
1333                 }
1334
1335                 public TypeSpec GetStackType (EmitContext ec)
1336                 {
1337                         var instance_type = instance.Type;
1338
1339                         if (addressRequired)
1340                                 return ReferenceContainer.MakeType (ec.Module, instance_type);
1341
1342                         if (instance_type.IsStructOrEnum)
1343                                 return ec.Module.Compiler.BuiltinTypes.Object;
1344
1345                         return instance_type;
1346                 }
1347
1348
1349         }
1350
1351         static class ExpressionAnalyzer
1352         {
1353                 public static bool RequiresBoxing (Expression instance)
1354                 {
1355                         var instance_type = instance.Type;
1356                         if (instance_type.IsGenericParameter && !(instance is This) && TypeSpec.IsReferenceType (instance_type))
1357                                 return true;
1358
1359                         if (instance_type.IsStructOrEnum)
1360                                 return true;
1361
1362                         return false;
1363                 }
1364
1365                 //
1366                 // Returns true for cheap race-free load, where we can avoid using dup
1367                 //
1368                 public static bool IsInexpensiveLoad (Expression instance)
1369                 {
1370                         if (instance is Constant)
1371                                 return instance.IsSideEffectFree;
1372
1373                         if (RequiresBoxing (instance))
1374                                 return false;
1375
1376                         var vr = instance as VariableReference;
1377                         if (vr != null) {
1378                                 // Load from captured local would be racy without dup
1379                                 return !vr.IsRef && !vr.IsHoisted;
1380                         }
1381
1382                         if (instance is LocalTemporary)
1383                                 return true;
1384
1385                         var fe = instance as FieldExpr;
1386                         if (fe != null)
1387                                 return fe.IsStatic || fe.InstanceExpression is This;
1388
1389                         return false;
1390                 }
1391         }
1392 }