Updated with Xamarin copyrights
[mono.git] / mcs / mcs / codegen.cs
index a03c6d0a9f249fc0540399108313d43fd9ec390b..142f9409343c47bb26479f1702874ca3b3c8771d 100644 (file)
@@ -7,6 +7,7 @@
 //
 // Copyright 2001, 2002, 2003 Ximian, Inc.
 // Copyright 2004 Novell, Inc.
+// Copyright 2011 Xamarin Inc
 //
 
 using System;
@@ -51,16 +52,6 @@ namespace Mono.CSharp
                /// </summary>
                public LocalBuilder return_value;
 
-               /// <summary>
-               ///   The location where return has to jump to return the
-               ///   value
-               /// </summary>
-               public Label ReturnLabel;
-
-               /// <summary>
-               ///   If we already defined the ReturnLabel
-               /// </summary>
-               public bool HasReturnLabel;
 
                /// <summary>
                ///   Current loop begin and end labels.
@@ -87,15 +78,17 @@ namespace Mono.CSharp
 
                DynamicSiteClass dynamic_site_container;
 
-               TypeSpec[] stack_types;
+               Label? return_label;
 
                public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
                {
                        this.member_context = rc;
                        this.ig = ig;
-
                        this.return_type = return_type;
 
+                       if (rc.Module.Compiler.Settings.Checked)
+                               flags |= Options.CheckedScope;
+
 #if STATIC
                        ig.__CleverExceptionBlockAssistance ();
 #endif
@@ -127,6 +120,12 @@ namespace Mono.CSharp
                        get { return member_context.CurrentMemberDefinition; }
                }
 
+               public bool HasReturnLabel {
+                       get {
+                               return return_label.HasValue;
+                       }
+               }
+
                public bool IsStatic {
                        get { return member_context.IsStatic; }
                }
@@ -165,27 +164,26 @@ namespace Mono.CSharp
                        }
                }
 
-               public int StackHeight {
-                       get {
-#if STATIC
-                               return ig.__StackHeight;
-#else
-                               throw new NotImplementedException ();
-#endif
-                       }
-               }
-
                //
-               // Enabled when tracking stack types during emit phase
+               // The label where we have to jump before leaving the context
                //
-               bool TrackStackTypes {
+               public Label ReturnLabel {
                        get {
-                               return (flags & Options.AsyncBody) != 0;
+                               return return_label.Value;
                        }
                }
 
                #endregion
 
+               public void AssertEmptyStack ()
+               {
+#if STATIC
+                       if (ig.__StackHeight != 0)
+                               throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
+                                       member_context.GetSignatureForError ());
+#endif
+               }
+
                /// <summary>
                ///   This is called immediately before emitting an IL opcode to tell the symbol
                ///   writer to which source line this opcode belongs.
@@ -256,6 +254,14 @@ namespace Mono.CSharp
                        return dynamic_site_container;
                }
 
+               public Label CreateReturnLabel ()
+               {
+                       if (!return_label.HasValue)
+                               return_label = DefineLabel ();
+
+                       return return_label.Value;
+               }
+
                public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
                {
                        if (IsAnonymousStoreyMutateRequired)
@@ -275,7 +281,7 @@ namespace Mono.CSharp
                public FieldExpr GetTemporaryField (TypeSpec type)
                {
                        var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
-                       var fexpr = new FieldExpr (f, Location.Null);
+                       var fexpr = new StackFieldExpr (f);
                        fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
                        return fexpr;
                }
@@ -288,88 +294,26 @@ namespace Mono.CSharp
                public void Emit (OpCode opcode)
                {
                        ig.Emit (opcode);
-
-                       if (TrackStackTypes) {
-                               switch (opcode.StackBehaviourPush) {
-                               case StackBehaviour.Push0:
-                                       // Nothing
-                                       break;
-                               case StackBehaviour.Pushi:
-                                       SetStackType (Module.Compiler.BuiltinTypes.Int);
-                                       break;
-                               case StackBehaviour.Pushi8:
-                                       SetStackType (Module.Compiler.BuiltinTypes.Long);
-                                       break;
-                               case StackBehaviour.Pushr4:
-                                       SetStackType (Module.Compiler.BuiltinTypes.Float);
-                                       break;
-                               case StackBehaviour.Pushr8:
-                                       SetStackType (Module.Compiler.BuiltinTypes.Double);
-                                       break;
-                               case StackBehaviour.Push1:
-                                       if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
-                                               // nothing
-                                       } else if (opcode.StackBehaviourPop == StackBehaviour.Pop1_pop1) {
-                                               // nothing
-                                       } else {
-                                               throw new NotImplementedException (opcode.Name);
-                                       }
-                                       break;
-                               case StackBehaviour.Push1_push1:
-                                       if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
-                                               SetStackType (stack_types[StackHeight - 2]);
-                                       } else {
-                                               throw new NotImplementedException (opcode.Name);
-                                       }
-                                       break;
-                               default:
-                                       throw new NotImplementedException (opcode.Name);
-                               }
-                       }
                }
 
-               public void Emit (OpCode opcode, LocalBuilder local, TypeSpec type)
+               public void Emit (OpCode opcode, LocalBuilder local)
                {
                        ig.Emit (opcode, local);
-
-                       if (TrackStackTypes) {
-                               if (opcode.StackBehaviourPush == StackBehaviour.Push0) {
-                                       // Nothing
-                               } else if (opcode.StackBehaviourPush == StackBehaviour.Push1) {
-                                       SetStackType (type);
-                               } else if (opcode.StackBehaviourPush == StackBehaviour.Pushi) {
-                                       SetStackType (ReferenceContainer.MakeType (Module, type));
-                               } else {
-                                       throw new NotImplementedException (opcode.Name);
-                               }
-                       }
                }
 
                public void Emit (OpCode opcode, string arg)
                {
                        ig.Emit (opcode, arg);
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.String);
-                       }
                }
 
                public void Emit (OpCode opcode, double arg)
                {
                        ig.Emit (opcode, arg);
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.Double);
-                       }
                }
 
                public void Emit (OpCode opcode, float arg)
                {
                        ig.Emit (opcode, arg);
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.Float);
-                       }
                }
 
                public void Emit (OpCode opcode, Label label)
@@ -388,29 +332,6 @@ namespace Mono.CSharp
                                type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
 
                        ig.Emit (opcode, type.GetMetaInfo ());
-
-                       if (TrackStackTypes) {
-                               switch (opcode.StackBehaviourPush) {
-                               case StackBehaviour.Push0:
-                                       // Nothing
-                                       break;
-                               case StackBehaviour.Pushi:
-                                       SetStackType (ReferenceContainer.MakeType (Module, type));
-                                       break;
-                               case StackBehaviour.Push1:
-                                       SetStackType (type);
-                                       break;
-                               default:
-                                       if (opcode == OpCodes.Box) {
-                                               SetStackType (Module.Compiler.BuiltinTypes.Object);
-                                       } else if (opcode == OpCodes.Castclass) {
-                                               SetStackType (type);
-                                       } else {
-                                               throw new NotImplementedException (opcode.Name);
-                                       }
-                                       break;
-                               }
-                       }
                }
 
                public void Emit (OpCode opcode, FieldSpec field)
@@ -419,22 +340,6 @@ namespace Mono.CSharp
                                field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
 
                        ig.Emit (opcode, field.GetMetaInfo ());
-
-                       if (TrackStackTypes) {
-                               switch (opcode.StackBehaviourPush) {
-                               case StackBehaviour.Push0:
-                                       // nothing
-                                       break;
-                               case StackBehaviour.Push1:
-                                       SetStackType (field.MemberType);
-                                       break;
-                               case StackBehaviour.Pushi:
-                                       SetStackType (ReferenceContainer.MakeType (Module, field.MemberType));
-                                       break;
-                               default:
-                                       throw new NotImplementedException ();
-                               }
-                       }
                }
 
                public void Emit (OpCode opcode, MethodSpec method)
@@ -446,20 +351,6 @@ namespace Mono.CSharp
                                ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
                        else
                                ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
-
-                       if (TrackStackTypes) {
-                               //
-                               // Don't bother with ldftn/Ldvirtftn they can never appear on open stack
-                               //
-                               if (method.IsConstructor) {
-                                       if (opcode == OpCodes.Newobj)
-                                               SetStackType (method.DeclaringType);
-                               } else {
-                                       if (method.ReturnType.Kind != MemberKind.Void) {
-                                               SetStackType (method.ReturnType);
-                                       }
-                               }
-                       }
                }
 
                // TODO: REMOVE breaks mutator
@@ -488,10 +379,6 @@ namespace Mono.CSharp
 
                                ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
                        }
-
-                       if (TrackStackTypes) {
-                               SetStackType (ac);
-                       }
                }
 
                public void EmitArrayAddress (ArrayContainer ac)
@@ -501,20 +388,12 @@ namespace Mono.CSharp
                                        ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
 
                                ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
-
-                               if (TrackStackTypes) {
-                                       SetStackType (ReferenceContainer.MakeType (Module, ac.Element));
-                               }
                        } else {
                                var type = IsAnonymousStoreyMutateRequired ?
                                        CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
                                        ac.Element;
 
                                ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
-
-                               if (TrackStackTypes) {
-                                       SetStackType (ReferenceContainer.MakeType (Module, type));
-                               }
                        }
                }
 
@@ -528,11 +407,6 @@ namespace Mono.CSharp
                                        ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
 
                                ig.Emit (OpCodes.Call, ac.GetGetMethod ());
-
-                               if (TrackStackTypes) {
-                                       SetStackType (ac.Element);
-                               }
-
                                return;
                        }
 
@@ -599,10 +473,6 @@ namespace Mono.CSharp
                                }
                                break;
                        }
-
-                       if (TrackStackTypes) {
-                               SetStackType (type);
-                       }
                }
 
                //
@@ -669,10 +539,6 @@ namespace Mono.CSharp
                public void EmitInt (int i)
                {
                        EmitIntConstant (i);
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.Int);
-                       }
                }
 
                void EmitIntConstant (int i)
@@ -738,10 +604,6 @@ namespace Mono.CSharp
                        } else {
                                ig.Emit (OpCodes.Ldc_I8, l);
                        }
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.Long);
-                       }
                }
 
                //
@@ -804,20 +666,11 @@ namespace Mono.CSharp
                                }
                                break;
                        }
-
-                       if (TrackStackTypes) {
-                               // TODO: test for async when `this' can be used inside structs
-                               SetStackType (type);
-                       }
                }
 
                public void EmitNull ()
                {
                        ig.Emit (OpCodes.Ldnull);
-
-                       if (TrackStackTypes) {
-                               SetStackType (Module.Compiler.BuiltinTypes.Object);
-                       }
                }
 
                public void EmitArgumentAddress (int pos)
@@ -829,13 +682,6 @@ namespace Mono.CSharp
                                ig.Emit (OpCodes.Ldarga, pos);
                        else
                                ig.Emit (OpCodes.Ldarga_S, (byte) pos);
-
-                       if (TrackStackTypes) {
-                               //
-                               // Should never be reached, all parameters are hoisted into class
-                               //
-                               throw new NotImplementedException ();
-                       }
                }
 
                public void EmitArgumentLoad (int pos)
@@ -855,13 +701,6 @@ namespace Mono.CSharp
                                        ig.Emit (OpCodes.Ldarg_S, (byte) pos);
                                break;
                        }
-
-                       if (TrackStackTypes) {
-                               //
-                               // Should never be reached, all parameters are hoisted into class
-                               //
-                               throw new NotImplementedException ();
-                       }
                }
 
                public void EmitArgumentStore (int pos)
@@ -930,24 +769,6 @@ namespace Mono.CSharp
                public void EmitThis ()
                {
                        ig.Emit (OpCodes.Ldarg_0);
-
-                       if (TrackStackTypes) {
-                               //
-                               // Using CurrentTypeOnStack as a placeholder for CurrentType to allow
-                               // optimizations based on `this' presence
-                               //
-                               SetStackType (InternalType.CurrentTypeOnStack);
-                       }
-               }
-
-               //
-               // Returns actual stack types when stack types tracing is enabled
-               //
-               public TypeSpec[] GetStackTypes ()
-               {
-                       TypeSpec[] types = new TypeSpec[StackHeight];
-                       Array.Copy (stack_types, types, types.Length);
-                       return types;
                }
 
                /// <summary>
@@ -994,20 +815,6 @@ namespace Mono.CSharp
                        s.Push (b);
                }
 
-               void SetStackType (TypeSpec type)
-               {
-                       if (type == null)
-                               throw new ArgumentNullException ("type");
-
-                       if (stack_types == null) {
-                               stack_types = new TypeSpec[8];
-                       } else if (StackHeight > stack_types.Length) {
-                               Array.Resize (ref stack_types, stack_types.Length * 2);
-                       }
-
-                       stack_types[StackHeight - 1] = type;
-               }
-
                /// <summary>
                ///   ReturnValue creates on demand the LocalBuilder for the
                ///   return value from the function.  By default this is not
@@ -1024,10 +831,6 @@ namespace Mono.CSharp
                {
                        if (return_value == null){
                                return_value = DeclareLocal (return_type, false);
-                               if (!HasReturnLabel){
-                                       ReturnLabel = DefineLabel ();
-                                       HasReturnLabel = true;
-                               }
                        }
 
                        return return_value;
@@ -1073,15 +876,15 @@ namespace Mono.CSharp
                {
                        Expression instance_copy = null;
 
-                       if (!HasAwaitArguments) {
+                       if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
                                HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
-                               if (HasAwaitArguments) {
-                                       if (InstanceExpressionOnStack)
-                                               throw new NotSupportedException ();
+                               if (HasAwaitArguments && InstanceExpressionOnStack) {
+                                       throw new NotSupportedException ();
                                }
                        }
 
                        OpCode call_op;
+                       LocalTemporary lt = null;
 
                        if (method.IsStatic) {
                                call_op = OpCodes.Call;
@@ -1102,7 +905,7 @@ namespace Mono.CSharp
                                        if (DuplicateArguments) {
                                                ec.Emit (OpCodes.Dup);
                                                if (Arguments != null && Arguments.Count != 0) {
-                                                       var lt = new LocalTemporary (instance_on_stack_type);
+                                                       lt = new LocalTemporary (instance_on_stack_type);
                                                        lt.Store (ec);
                                                        instance_copy = lt;
                                                }
@@ -1116,7 +919,6 @@ namespace Mono.CSharp
                                        if (instance_copy != null) {
                                                EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
 
-                                               var lt = instance_copy as LocalTemporary;
                                                if (lt != null)
                                                        lt.Release (ec);
                                        }
@@ -1157,7 +959,7 @@ namespace Mono.CSharp
                        //
                        // Push the instance expression
                        //
-                       if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType == instance_type))) ||
+                       if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
                                instance_type.IsGenericParameter || declaringType.IsNullableType) {
                                //
                                // If the expression implements IMemoryLocation, then
@@ -1174,7 +976,6 @@ namespace Mono.CSharp
                                        instance.Emit (ec);
                                        temp.Store (ec);
                                        temp.AddressOf (ec, AddressOp.Load);
-                                       temp.Release (ec);
                                }
 
                                return ReferenceContainer.MakeType (ec.Module, instance_type);