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