Exemple #1
0
        public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
        {
            if (prepare_for_load)
            {
                throw new NotImplementedException();
            }

            source.Emit(ec);

            Store(ec);

            if (leave_copy)
            {
                Emit(ec);
            }
        }
Exemple #2
0
        public virtual void Emit(EmitContext ec)
        {
            if (!IsByRef)
            {
                Expr.Emit(ec);
                return;
            }

            AddressOp mode = AddressOp.Store;

            if (ArgType == AType.Ref)
            {
                mode |= AddressOp.Load;
            }

            IMemoryLocation ml = (IMemoryLocation)Expr;

            ml.AddressOf(ec, mode);
        }
Exemple #3
0
                protected override void DoEmit(EmitContext ec)
                {
                    Label label_init = ec.DefineLabel();

                    ec.Emit(OpCodes.Ldarg_0);
                    ec.Emit(OpCodes.Ldflda, host.PC.Spec);
                    ec.EmitInt((int)Iterator.State.Start);
                    ec.EmitInt((int)Iterator.State.Uninitialized);
                    ec.Emit(OpCodes.Call, TypeManager.int_interlocked_compare_exchange);

                    ec.EmitInt((int)Iterator.State.Uninitialized);
                    ec.Emit(OpCodes.Bne_Un_S, label_init);

                    ec.Emit(OpCodes.Ldarg_0);
                    ec.Emit(OpCodes.Ret);

                    ec.MarkLabel(label_init);

                    new_storey.Emit(ec);
                    ec.Emit(OpCodes.Ret);
                }
                protected override void DoEmit(EmitContext ec)
                {
                    ILGenerator ig         = ec.ig;
                    Label       label_init = ig.DefineLabel();

                    ig.Emit(OpCodes.Ldarg_0);
                    ig.Emit(OpCodes.Ldflda, host.PC.FieldBuilder);
                    IntConstant.EmitInt(ig, (int)Iterator.State.Start);
                    IntConstant.EmitInt(ig, (int)Iterator.State.Uninitialized);
                    ig.Emit(OpCodes.Call, TypeManager.int_interlocked_compare_exchange);

                    IntConstant.EmitInt(ig, (int)Iterator.State.Uninitialized);
                    ig.Emit(OpCodes.Bne_Un_S, label_init);

                    ig.Emit(OpCodes.Ldarg_0);
                    ig.Emit(OpCodes.Ret);

                    ig.MarkLabel(label_init);

                    new_storey.Emit(ec);
                    ig.Emit(OpCodes.Ret);
                }
Exemple #5
0
        public override void Emit(EmitContext ec)
        {
            if (delegate_instance_expression == null)
            {
                ec.ig.Emit(OpCodes.Ldnull);
            }
            else
            {
                delegate_instance_expression.Emit(ec);
            }

            if (!delegate_method.DeclaringType.IsSealed && delegate_method.IsVirtual && !method_group.IsBase)
            {
                ec.ig.Emit(OpCodes.Dup);
                ec.ig.Emit(OpCodes.Ldvirtftn, delegate_method);
            }
            else
            {
                ec.ig.Emit(OpCodes.Ldftn, delegate_method);
            }

            ec.ig.Emit(OpCodes.Newobj, constructor_method);
        }
Exemple #6
0
        //
        // Called back from Yield
        //
        public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
        {
            // Store the new current
            ec.Emit(OpCodes.Ldarg_0);
            expr.Emit(ec);
            ec.Emit(OpCodes.Stfld, IteratorHost.CurrentField.Spec);

            // store resume program-counter
            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt(resume_pc);
            ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec);

            // mark finally blocks as disabled
            if (unwind_protect && skip_finally != null)
            {
                ec.EmitInt(1);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }

            // Return ok
            ec.Emit(unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);

            ec.MarkLabel(resume_point);
        }
Exemple #7
0
        //
        // Called back from Yield
        //
        public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
        {
            // Store the new current
            ec.Emit(OpCodes.Ldarg_0);
            expr.Emit(ec);
            ec.Emit(OpCodes.Stfld, IteratorHost.CurrentField.Spec);

            //
            // Guard against being disposed meantime
            //
            Label disposed = ec.DefineLabel();

            ec.Emit(OpCodes.Ldarg_0);
            ec.Emit(OpCodes.Ldfld, IteratorHost.DisposingField.Spec);
            ec.Emit(OpCodes.Brtrue_S, disposed);

            //
            // store resume program-counter
            //
            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt(resume_pc);
            ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec);
            ec.MarkLabel(disposed);

            // mark finally blocks as disabled
            if (unwind_protect && skip_finally != null)
            {
                ec.EmitInt(1);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }

            // Return ok
            ec.Emit(unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);

            ec.MarkLabel(resume_point);
        }
		// `dup_args' leaves an extra copy of the arguments on the stack
		// `omit_args' does not leave any arguments at all.
		// So, basically, you could make one call with `dup_args' set to true,
		// and then another with `omit_args' set to true, and the two calls
		// would have the same set of arguments. However, each argument would
		// only have been evaluated once.
		public static void EmitCall (EmitContext ec, bool is_base,
					     Expression instance_expr,
					     MethodBase method, Arguments Arguments, Location loc,
		                             bool dup_args, bool omit_args)
		{
			ILGenerator ig = ec.ig;
			bool struct_call = false;
			bool this_call = false;
			LocalTemporary this_arg = null;

			Type decl_type = method.DeclaringType;

			if (IsMethodExcluded (method, loc))
				return;
			
			bool is_static = method.IsStatic;
			if (!is_static){
				this_call = instance_expr is This;
				if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
					struct_call = true;

				//
				// If this is ourselves, push "this"
				//
				if (!omit_args) {
					Type t = null;
					Type iexpr_type = instance_expr.Type;

					//
					// Push the instance expression
					//
					if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
						//
						// Special case: calls to a function declared in a 
						// reference-type with a value-type argument need
						// to have their value boxed.
						if (TypeManager.IsStruct (decl_type) ||
						    TypeManager.IsGenericParameter (iexpr_type)) {
							//
							// If the expression implements IMemoryLocation, then
							// we can optimize and use AddressOf on the
							// return.
							//
							// If not we have to use some temporary storage for
							// it.
							if (instance_expr is IMemoryLocation) {
								((IMemoryLocation)instance_expr).
									AddressOf (ec, AddressOp.LoadStore);
							} else {
								LocalTemporary temp = new LocalTemporary (iexpr_type);
								instance_expr.Emit (ec);
								temp.Store (ec);
								temp.AddressOf (ec, AddressOp.Load);
							}

							// avoid the overhead of doing this all the time.
							if (dup_args)
								t = TypeManager.GetReferenceType (iexpr_type);
						} else {
							instance_expr.Emit (ec);
							
							// FIXME: should use instance_expr is IMemoryLocation + constraint.
							// to help JIT to produce better code
							ig.Emit (OpCodes.Box, instance_expr.Type);
							t = TypeManager.object_type;
						}
					} else {
						instance_expr.Emit (ec);
						t = instance_expr.Type;
					}

					if (dup_args) {
						ig.Emit (OpCodes.Dup);
						if (Arguments != null && Arguments.Count != 0) {
							this_arg = new LocalTemporary (t);
							this_arg.Store (ec);
						}
					}
				}
			}

			if (!omit_args && Arguments != null)
				Arguments.Emit (ec, dup_args, this_arg);

			OpCode call_op;
			if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
				call_op = OpCodes.Call;
			} else {
				call_op = OpCodes.Callvirt;
				
#if GMCS_SOURCE
				if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
					ig.Emit (OpCodes.Constrained, instance_expr.Type);
#endif
			}

			if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
				Type[] varargs_types = GetVarargsTypes (method, Arguments);
				ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
				return;
			}

			//
			// If you have:
			// this.DoFoo ();
			// and DoFoo is not virtual, you can omit the callvirt,
			// because you don't need the null checking behavior.
			//
			if (method is MethodInfo)
				ig.Emit (call_op, (MethodInfo) method);
			else
				ig.Emit (call_op, (ConstructorInfo) method);
		}
Exemple #9
0
		/// <remarks>
		///   is_base tells whether we want to force the use of the `call'
		///   opcode instead of using callvirt.  Call is required to call
		///   a specific method, while callvirt will always use the most
		///   recent method in the vtable.
		///
		///   is_static tells whether this is an invocation on a static method
		///
		///   instance_expr is an expression that represents the instance
		///   it must be non-null if is_static is false.
		///
		///   method is the method to invoke.
		///
		///   Arguments is the list of arguments to pass to the method or constructor.
		/// </remarks>
		public static void EmitCall (EmitContext ec, bool is_base,
					     bool is_static, Expression instance_expr,
					     MethodBase method, ArrayList Arguments, Location loc)
		{
			ILGenerator ig = ec.ig;
			bool struct_call = false;

			Type decl_type = method.DeclaringType;

			if (!RootContext.StdLib) {
				// Replace any calls to the system's System.Array type with calls to
				// the newly created one.
				if (method == TypeManager.system_int_array_get_length)
					method = TypeManager.int_array_get_length;
				else if (method == TypeManager.system_int_array_get_rank)
					method = TypeManager.int_array_get_rank;
				else if (method == TypeManager.system_object_array_clone)
					method = TypeManager.object_array_clone;
				else if (method == TypeManager.system_int_array_get_length_int)
					method = TypeManager.int_array_get_length_int;
				else if (method == TypeManager.system_int_array_get_lower_bound_int)
					method = TypeManager.int_array_get_lower_bound_int;
				else if (method == TypeManager.system_int_array_get_upper_bound_int)
					method = TypeManager.int_array_get_upper_bound_int;
				else if (method == TypeManager.system_void_array_copyto_array_int)
					method = TypeManager.void_array_copyto_array_int;
			}

			//
			// This checks the `ConditionalAttribute' on the method, and the
			// ObsoleteAttribute
			//
			TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
			if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
				return;
			if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
				return;
			
			if (!is_static){
				if (decl_type.IsValueType)
					struct_call = true;
				//
				// If this is ourselves, push "this"
				//
				if (instance_expr == null){
					ig.Emit (OpCodes.Ldarg_0);
				} else {
					//
					// Push the instance expression
					//
					if (instance_expr.Type.IsValueType){
						//
						// Special case: calls to a function declared in a 
						// reference-type with a value-type argument need
						// to have their value boxed.  

						struct_call = true;
						if (decl_type.IsValueType){
							//
							// If the expression implements IMemoryLocation, then
							// we can optimize and use AddressOf on the
							// return.
							//
							// If not we have to use some temporary storage for
							// it.
							if (instance_expr is IMemoryLocation){
								((IMemoryLocation)instance_expr).
									AddressOf (ec, AddressOp.LoadStore);
							}
							else {
								Type t = instance_expr.Type;
								
								instance_expr.Emit (ec);
								LocalBuilder temp = ig.DeclareLocal (t);
								ig.Emit (OpCodes.Stloc, temp);
								ig.Emit (OpCodes.Ldloca, temp);
							}
						} else {
							instance_expr.Emit (ec);
							ig.Emit (OpCodes.Box, instance_expr.Type);
						} 
					} else
						instance_expr.Emit (ec);
				}
			}

			EmitArguments (ec, method, Arguments);

			if (is_static || struct_call || is_base){
				if (method is MethodInfo) {
					ig.Emit (OpCodes.Call, (MethodInfo) method);
				} else
					ig.Emit (OpCodes.Call, (ConstructorInfo) method);
			} else {
				if (method is MethodInfo)
					ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
				else
					ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
			}
		}
Exemple #10
0
		public void EmitAssign (EmitContext ec, Expression source)
		{
			ILGenerator ig = ec.ig;
			
			if (ec.TypeContainer is Struct){
				ig.Emit (OpCodes.Ldarg_0);
				source.Emit (ec);
				ig.Emit (OpCodes.Stobj, type);
			} else {
				source.Emit (ec);
				ig.Emit (OpCodes.Starg, 0);
			}
		}
Exemple #11
0
        //
        // Implements the IAssignMethod interface for assignments
        //
        public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
        {
            Expression my_source = source;

            if (prepare_for_load) {
                prepared = true;
                source.Emit (ec);

                if (leave_copy) {
                    ec.Emit (OpCodes.Dup);
                    if (!IsStatic) {
                        temp = new LocalTemporary (this.Type);
                        temp.Store (ec);
                    }
                }
            } else if (leave_copy) {
                source.Emit (ec);
                temp = new LocalTemporary (this.Type);
                temp.Store (ec);
                my_source = temp;
            }

            Arguments args = new Arguments (1);
            args.Add (new Argument (my_source));

            Invocation.EmitCall (ec, IsBase, InstanceExpression, spec.Set, args, loc, false, prepared);

            if (temp != null) {
                temp.Emit (ec);
                temp.Release (ec);
            }
        }
Exemple #12
0
        public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
        {
            prepared = prepare_for_load;
            EmitInstance (ec, prepared);

            source.Emit (ec);
            if (leave_copy) {
                ec.Emit (OpCodes.Dup);
                if (!IsStatic) {
                    temp = new LocalTemporary (this.Type);
                    temp.Store (ec);
                }
            }

            if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
                ec.Emit (OpCodes.Volatile);

            spec.MemberDefinition.SetIsAssigned ();

            if (IsStatic)
                ec.Emit (OpCodes.Stsfld, spec);
            else
                ec.Emit (OpCodes.Stfld, spec);

            if (temp != null) {
                temp.Emit (ec);
                temp.Release (ec);
                temp = null;
            }
        }
Exemple #13
0
		public void EmitAssign (EmitContext ec, Expression source)
		{
			ILGenerator ig = ec.ig;
			int arg_idx = idx;

			if (!ec.IsStatic)
				arg_idx++;

			if (is_ref)
				EmitLdArg (ig, arg_idx);
			
			source.Emit (ec);

			if (is_ref)
				StoreFromPtr (ig, type);
			else {
				if (arg_idx <= 255)
					ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
				else
					ig.Emit (OpCodes.Starg, arg_idx);
			}
		}
Exemple #14
0
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
		{
			if (isCompound)
				throw new NotImplementedException ();

			source.Emit (ec);

			Store (ec);

			if (leave_copy)
				Emit (ec);
		}
Exemple #15
0
		public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast)
		{
			TypeSpec expr_type = expr.Type;

			if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
				// if we are a method group, emit a warning

				expr.Emit (null);
			}

			if (expr_type == TypeManager.void_type)
				return null;

			if (expr_type.Kind == MemberKind.TypeParameter)
				return ImplicitTypeParameterConversion (expr, target_type);

			//
			// from the null type to any reference-type.
			//
			NullLiteral nl = expr as NullLiteral;
			if (nl != null) {
				return nl.ConvertImplicitly (null, target_type);
			}

			if (ImplicitReferenceConversionExists (expr, target_type)) {
				// 
				// Avoid wrapping implicitly convertible reference type
				//
				if (!explicit_cast)
					return expr;

				return EmptyCast.Create (expr, target_type);
			}

			return ImplicitBoxingConversion (expr, expr_type, target_type);
		}
Exemple #16
0
		public void EmitAssign (EmitContext ec, Expression source)
		{
			if (temporary != null){
				if (have_temporary)
					temporary.Emit (ec);
				else {
					expr.Emit (ec);
					ec.ig.Emit (OpCodes.Dup);
					temporary.Store (ec);
					have_temporary = true;
				}
			} else
				expr.Emit (ec);

			source.Emit (ec);
			StoreFromPtr (ec.ig, type);
		}
Exemple #17
0
		public void EmitAssign (EmitContext ec, Expression source)
		{
			int rank = ea.Expr.Type.GetArrayRank ();
			ILGenerator ig = ec.ig;
			Type t = source.Type;

			LoadArrayAndArguments (ec);

			//
			// The stobj opcode used by value types will need
			// an address on the stack, not really an array/array
			// pair
			//
			if (rank == 1){
				if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
				    (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
					ig.Emit (OpCodes.Ldelema, t);
			}
			
			source.Emit (ec);

			if (rank == 1)
				EmitStoreOpcode (ig, t);
			else {
				ModuleBuilder mb = CodeGen.ModuleBuilder;
				int arg_count = ea.Arguments.Count;
				Type [] args = new Type [arg_count + 1];
				MethodInfo set;
				
				for (int i = 0; i < arg_count; i++){
					//args [i++] = a.Type;
					args [i] = TypeManager.int32_type;
				}

				args [arg_count] = type;
				
				set = mb.GetArrayMethod (
					ea.Expr.Type, "Set",
					CallingConventions.HasThis |
					CallingConventions.Standard,
					TypeManager.void_type, args);
				
				ig.Emit (OpCodes.Call, set);
			}
		}
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
					bool prepare_for_load)
		{
			HoistedVariable hv = GetHoistedVariable (ec);
			if (hv != null) {
				hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
				return;
			}

			New n_source = source as New;
			if (n_source != null) {
				if (!n_source.Emit (ec, this)) {
					if (leave_copy)
						EmitLoad (ec);
					return;
				}
			} else {
				if (IsRef)
					EmitLoad (ec);

				source.Emit (ec);
			}

			if (leave_copy) {
				ec.ig.Emit (OpCodes.Dup);
				if (IsRef) {
					temp = new LocalTemporary (Type);
					temp.Store (ec);
				}
			}

			if (IsRef)
				StoreFromPtr (ec.ig, type);
			else
				Variable.EmitAssign (ec);

			if (temp != null) {
				temp.Emit (ec);
				temp.Release (ec);
			}
		}
		//
		// Called back from Yield
		//
		public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
		{
			ILGenerator ig = ec.ig;

			// Store the new current
			ig.Emit (OpCodes.Ldarg_0);
			expr.Emit (ec);
			ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);

			// store resume program-counter
			ig.Emit (OpCodes.Ldarg_0);
			IntConstant.EmitInt (ig, resume_pc);
			ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);

			// mark finally blocks as disabled
			if (unwind_protect && skip_finally != null) {
				ig.Emit (OpCodes.Ldc_I4_1);
				ig.Emit (OpCodes.Stloc, skip_finally);
			}

			// Return ok
			ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);

			ig.MarkLabel (resume_point);
		}
Exemple #20
0
		//
		// Called back from Yield
		//
		public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
		{
			// Store the new current
			ec.Emit (OpCodes.Ldarg_0);
			expr.Emit (ec);
			ec.Emit (OpCodes.Stfld, IteratorHost.CurrentField.Spec);

			//
			// Guard against being disposed meantime
			//
			Label disposed = ec.DefineLabel ();
			ec.Emit (OpCodes.Ldarg_0);
			ec.Emit (OpCodes.Ldfld, IteratorHost.DisposingField.Spec);
			ec.Emit (OpCodes.Brtrue_S, disposed);

			//
			// store resume program-counter
			//
			ec.Emit (OpCodes.Ldarg_0);
			ec.EmitInt (resume_pc);
			ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec);
			ec.MarkLabel (disposed);

			// mark finally blocks as disabled
			if (unwind_protect && skip_finally != null) {
				ec.EmitInt (1);
				ec.Emit (OpCodes.Stloc, skip_finally);
			}

			// Return ok
			ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);

			ec.MarkLabel (resume_point);
		}
		static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast)
		{
			Type expr_type = expr.Type;

			if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
				// if we are a method group, emit a warning

				expr.Emit (null);
			}

			if (expr_type == TypeManager.void_type)
				return null;

			if (TypeManager.IsGenericParameter (expr_type))
				return ImplicitTypeParameterConversion (expr, target_type);

			//
			// from the null type to any reference-type.
			//
			NullLiteral nl = expr as NullLiteral;
			if (nl != null) {
				return nl.ConvertImplicitly(target_type);
			}

			if (ImplicitReferenceConversionExists (expr, target_type)) {
				// 
				// Avoid wrapping implicitly convertible reference type
				//
				if (!explicit_cast)
					return expr;

				return EmptyCast.Create (expr, target_type);
			}

			bool use_class_cast;
			if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) {
				if (use_class_cast)
					return new ClassCast (expr, target_type);
				else
					return new BoxedCast (expr, target_type);
			}

			return null;
		}
Exemple #22
0
		/// <summary>
		/// This method emits code for a lookup-based switch statement (non-string)
		/// Basically it groups the cases into blocks that are at least half full,
		/// and then spits out individual lookup opcodes for each block.
		/// It emits the longest blocks first, and short blocks are just
		/// handled with direct compares.
		/// </summary>
		/// <param name="ec"></param>
		/// <param name="val"></param>
		/// <returns></returns>
		void TableSwitchEmit (EmitContext ec, Expression val)
		{
			int element_count = Elements.Count;
			object [] element_keys = new object [element_count];
			Elements.Keys.CopyTo (element_keys, 0);
			Array.Sort (element_keys);

			// initialize the block list with one element per key
			var key_blocks = new List<KeyBlock> (element_count);
			foreach (object key in element_keys)
				key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));

			KeyBlock current_kb;
			// iteratively merge the blocks while they are at least half full
			// there's probably a really cool way to do this with a tree...
			while (key_blocks.Count > 1)
			{
				var key_blocks_new = new List<KeyBlock> ();
				current_kb = (KeyBlock) key_blocks [0];
				for (int ikb = 1; ikb < key_blocks.Count; ikb++)
				{
					KeyBlock kb = (KeyBlock) key_blocks [ikb];
					if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
					{
						// merge blocks
						current_kb.last = kb.last;
						current_kb.Size += kb.Size;
					}
					else
					{
						// start a new block
						key_blocks_new.Add (current_kb);
						current_kb = kb;
					}
				}
				key_blocks_new.Add (current_kb);
				if (key_blocks.Count == key_blocks_new.Count)
					break;
				key_blocks = key_blocks_new;
			}

			// initialize the key lists
			foreach (KeyBlock kb in key_blocks)
				kb.element_keys = new List<object> ();

			// fill the key lists
			int iBlockCurr = 0;
			if (key_blocks.Count > 0) {
				current_kb = (KeyBlock) key_blocks [0];
				foreach (object key in element_keys)
				{
					bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
						System.Convert.ToInt64 (key) > current_kb.last;
					if (next_block)
						current_kb = (KeyBlock) key_blocks [++iBlockCurr];
					current_kb.element_keys.Add (key);
				}
			}

			// sort the blocks so we can tackle the largest ones first
			key_blocks.Sort ();

			// okay now we can start...
			Label lbl_end = ec.DefineLabel ();	// at the end ;-)
			Label lbl_default = default_target;

			Type type_keys = null;
			if (element_keys.Length > 0)
				type_keys = element_keys [0].GetType ();	// used for conversions

			TypeSpec compare_type;
			
			if (TypeManager.IsEnumType (SwitchType))
				compare_type = EnumSpec.GetUnderlyingType (SwitchType);
			else
				compare_type = SwitchType;
			
			for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
			{
				KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
				lbl_default = (iBlock == 0) ? default_target : ec.DefineLabel ();
				if (kb.Length <= 2)
				{
					foreach (object key in kb.element_keys) {
						SwitchLabel sl = (SwitchLabel) Elements [key];
						if (key is int && (int) key == 0) {
							val.EmitBranchable (ec, sl.GetILLabel (ec), false);
						} else {
							val.Emit (ec);
							EmitObjectInteger (ec, key);
							ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
						}
					}
				}
				else
				{
					// TODO: if all the keys in the block are the same and there are
					//       no gaps/defaults then just use a range-check.
					if (compare_type == TypeManager.int64_type ||
						compare_type == TypeManager.uint64_type)
					{
						// TODO: optimize constant/I4 cases

						// check block range (could be > 2^31)
						val.Emit (ec);
						EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
						ec.Emit (OpCodes.Blt, lbl_default);
						val.Emit (ec);
						EmitObjectInteger (ec, System.Convert.ChangeType (kb.last, type_keys));
						ec.Emit (OpCodes.Bgt, lbl_default);

						// normalize range
						val.Emit (ec);
						if (kb.first != 0)
						{
							EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
							ec.Emit (OpCodes.Sub);
						}
						ec.Emit (OpCodes.Conv_I4);	// assumes < 2^31 labels!
					}
					else
					{
						// normalize range
						val.Emit (ec);
						int first = (int) kb.first;
						if (first > 0)
						{
							ec.EmitInt (first);
							ec.Emit (OpCodes.Sub);
						}
						else if (first < 0)
						{
							ec.EmitInt (-first);
							ec.Emit (OpCodes.Add);
						}
					}

					// first, build the list of labels for the switch
					int iKey = 0;
					int cJumps = kb.Length;
					Label [] switch_labels = new Label [cJumps];
					for (int iJump = 0; iJump < cJumps; iJump++)
					{
						object key = kb.element_keys [iKey];
						if (System.Convert.ToInt64 (key) == kb.first + iJump)
						{
							SwitchLabel sl = (SwitchLabel) Elements [key];
							switch_labels [iJump] = sl.GetILLabel (ec);
							iKey++;
						}
						else
							switch_labels [iJump] = lbl_default;
					}
					// emit the switch opcode
					ec.Emit (OpCodes.Switch, switch_labels);
				}

				// mark the default for this block
				if (iBlock != 0)
					ec.MarkLabel (lbl_default);
			}

			// TODO: find the default case and emit it here,
			//       to prevent having to do the following jump.
			//       make sure to mark other labels in the default section

			// the last default just goes to the end
			if (element_keys.Length > 0)
				ec.Emit (OpCodes.Br, lbl_default);

			// now emit the code for the sections
			bool found_default = false;

			foreach (SwitchSection ss in Sections) {
				foreach (SwitchLabel sl in ss.Labels) {
					if (sl.Converted == SwitchLabel.NullStringCase) {
						ec.MarkLabel (null_target);
					} else if (sl.Label == null) {
						ec.MarkLabel (lbl_default);
						found_default = true;
						if (!has_null_case)
							ec.MarkLabel (null_target);
					}
					ec.MarkLabel (sl.GetILLabel (ec));
					ec.MarkLabel (sl.GetILLabelCode (ec));
				}
				ss.Block.Emit (ec);
			}
			
			if (!found_default) {
				ec.MarkLabel (lbl_default);
				if (!has_null_case) {
					ec.MarkLabel (null_target);
				}
			}
			
			ec.MarkLabel (lbl_end);
		}
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
		{
			int rank = ea.Expr.Type.GetArrayRank ();
			ILGenerator ig = ec.ig;
			Type t = source.Type;
			prepared = prepare_for_load;

			if (prepared) {
				AddressOf (ec, AddressOp.LoadStore);
				ec.ig.Emit (OpCodes.Dup);
			} else {
				LoadArrayAndArguments (ec);
			}

			if (rank == 1) {
				bool is_stobj, has_type_arg;
				OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);

				if (!prepared) {
					//
					// The stobj opcode used by value types will need
					// an address on the stack, not really an array/array
					// pair
					//
					if (is_stobj)
						ig.Emit (OpCodes.Ldelema, t);
				}
				
				source.Emit (ec);
				if (leave_copy) {
					ec.ig.Emit (OpCodes.Dup);
					temp = new LocalTemporary (this.type);
					temp.Store (ec);
				}
				
				if (prepared)
					StoreFromPtr (ig, t);
				else if (is_stobj)
					ig.Emit (OpCodes.Stobj, t);
				else if (has_type_arg)
					ig.Emit (op, t);
				else
					ig.Emit (op);
			} else {
				source.Emit (ec);
				if (leave_copy) {
					ec.ig.Emit (OpCodes.Dup);
					temp = new LocalTemporary (this.type);
					temp.Store (ec);
				}

				if (prepared) {
					StoreFromPtr (ig, t);
				} else {
					int arg_count = ea.Arguments.Count;
					Type [] args = new Type [arg_count + 1];
					for (int i = 0; i < arg_count; i++) {
						//args [i++] = a.Type;
						args [i] = TypeManager.int32_type;
					}
					args [arg_count] = type;

					MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
						ea.Expr.Type, "Set",
						CallingConventions.HasThis |
						CallingConventions.Standard,
						TypeManager.void_type, args);

					ig.Emit (OpCodes.Call, set);
				}
			}
			
			if (temp != null) {
				temp.Emit (ec);
				temp.Release (ec);
			}
		}
Exemple #24
0
		static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
		{
			var instance_type = instance.Type;

			//
			// Push the instance expression
			//
			if ((instance_type.IsStructOrEnum && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
				instance_type.IsGenericParameter || declaringType.IsNullableType) {
				//
				// If the expression implements IMemoryLocation, then
				// we can optimize and use AddressOf on the
				// return.
				//
				// If not we have to use some temporary storage for
				// it.
				var iml = instance as IMemoryLocation;
				if (iml != null) {
					iml.AddressOf (ec, AddressOp.Load);
				} else {
					LocalTemporary temp = new LocalTemporary (instance_type);
					instance.Emit (ec);
					temp.Store (ec);
					temp.AddressOf (ec, AddressOp.Load);
				}

				return ReferenceContainer.MakeType (ec.Module, instance_type);
			}

			if (instance_type.IsStructOrEnum) {
				instance.Emit (ec);
				ec.Emit (OpCodes.Box, instance_type);
				return ec.BuiltinTypes.Object;
			}

			instance.Emit (ec);
			return instance_type;
		}
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
		{
			prepared = prepare_for_load;
			
			expr.Emit (ec);

			if (prepare_for_load)
				ec.ig.Emit (OpCodes.Dup);
			
			source.Emit (ec);
			if (leave_copy) {
				ec.ig.Emit (OpCodes.Dup);
				temporary = new LocalTemporary (expr.Type);
				temporary.Store (ec);
			}
			
			StoreFromPtr (ec.ig, type);
			
			if (temporary != null) {
				temporary.Emit (ec);
				temporary.Release (ec);
			}
		}
Exemple #26
0
 public override void Emit(EmitContext ec)
 {
     child.Emit(ec);
 }
		//
		// source is ignored, because we already have a copy of it from the
		// LValue resolution and we have already constructed a pre-cached
		// version of the arguments (ea.set_arguments);
		//
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
		{
			prepared = prepare_for_load;
			Expression value = set_expr;

			if (prepared) {
				Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
					arguments, loc, true, false);

				prepared_value = new LocalTemporary (type);
				prepared_value.Store (ec);
				source.Emit (ec);
				prepared_value.Release (ec);

				if (leave_copy) {
					ec.ig.Emit (OpCodes.Dup);
					temp = new LocalTemporary (Type);
					temp.Store (ec);
				}
			} else if (leave_copy) {
				temp = new LocalTemporary (Type);
				source.Emit (ec);
				temp.Store (ec);
				value = temp;
			}
			
			if (!prepared)
				arguments.Add (new Argument (value));

			Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
			
			if (temp != null) {
				temp.Emit (ec);
				temp.Release (ec);
			}
		}
Exemple #28
0
        //
        // Called back from Yield
        //
        public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
        {
            // Store the new current
            ec.Emit (OpCodes.Ldarg_0);
            expr.Emit (ec);
            ec.Emit (OpCodes.Stfld, IteratorHost.CurrentField.Spec);

            // store resume program-counter
            ec.Emit (OpCodes.Ldarg_0);
            ec.EmitInt (resume_pc);
            ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec);

            // mark finally blocks as disabled
            if (unwind_protect && skip_finally != null) {
                ec.EmitInt (1);
                ec.Emit (OpCodes.Stloc, skip_finally);
            }

            // Return ok
            ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);

            ec.MarkLabel (resume_point);
        }
Exemple #29
0
		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
		{
			FieldAttributes fa = FieldInfo.Attributes;
			bool is_static = (fa & FieldAttributes.Static) != 0;
			bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
			ILGenerator ig = ec.ig;

			if (is_readonly && !ec.IsConstructor){
				Report_AssignToReadonly (source);
				return;
			}

			prepared = prepare_for_load;
			EmitInstance (ec, prepared);

			source.Emit (ec);
			if (leave_copy) {
				ec.ig.Emit (OpCodes.Dup);
				if (!FieldInfo.IsStatic) {
					temp = new LocalTemporary (this.Type);
					temp.Store (ec);
				}
			}

			FieldBase f = TypeManager.GetField (FieldInfo);
			if (f != null){
				if ((f.ModFlags & Modifiers.VOLATILE) != 0)
					ig.Emit (OpCodes.Volatile);
					
				f.SetAssigned ();
			}

			if (is_static)
				ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
			else
				ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
			
			if (temp != null) {
				temp.Emit (ec);
				temp.Release (ec);
				temp = null;
			}
		}
Exemple #30
0
        public void Emit(EmitContext ec, bool conditionalAccess)
        {
            Label NullOperatorLabel;

            Nullable.Unwrap unwrap;

            if (conditionalAccess && Expression.IsNeverNull(instance))
            {
                conditionalAccess = false;
            }

            if (conditionalAccess)
            {
                NullOperatorLabel = ec.DefineLabel();
                unwrap            = instance as Nullable.Unwrap;
            }
            else
            {
                NullOperatorLabel = new Label();
                unwrap            = null;
            }

            IMemoryLocation instance_address       = null;
            bool            conditional_access_dup = false;

            if (unwrap != null)
            {
                unwrap.Store(ec);
                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);
            }
            else
            {
                if (conditionalAccess && addressRequired)
                {
                    //
                    // Don't allocate temp variable when instance load is cheap and load and load-address
                    // operate on same memory
                    //
                    instance_address = instance as VariableReference;
                    if (instance_address == null)
                    {
                        instance_address = instance as LocalTemporary;
                    }

                    if (instance_address == null)
                    {
                        EmitLoad(ec, false);
                        ec.Emit(OpCodes.Dup);
                        ec.EmitLoadFromPtr(instance.Type);

                        conditional_access_dup = true;
                    }
                    else
                    {
                        instance.Emit(ec);
                    }
                }
                else
                {
                    EmitLoad(ec, !conditionalAccess);

                    if (conditionalAccess)
                    {
                        conditional_access_dup = !IsInexpensiveLoad();
                        if (conditional_access_dup)
                        {
                            ec.Emit(OpCodes.Dup);
                        }
                    }
                }

                if (conditionalAccess)
                {
                    if (instance.Type.Kind == MemberKind.TypeParameter)
                    {
                        ec.Emit(OpCodes.Box, instance.Type);
                    }

                    ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);

                    if (conditional_access_dup)
                    {
                        ec.Emit(OpCodes.Pop);
                    }
                }
            }

            if (conditionalAccess)
            {
                if (!ec.ConditionalAccess.Statement)
                {
                    if (ec.ConditionalAccess.Type.IsNullableType)
                    {
                        Nullable.LiftedNull.Create(ec.ConditionalAccess.Type, Location.Null).Emit(ec);
                    }
                    else
                    {
                        ec.EmitNull();
                    }
                }

                ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel);
                ec.MarkLabel(NullOperatorLabel);

                if (instance_address != null)
                {
                    instance_address.AddressOf(ec, AddressOp.Load);
                }
                else if (unwrap != null)
                {
                    unwrap.Emit(ec);
                    var tmp = ec.GetTemporaryLocal(unwrap.Type);
                    ec.Emit(OpCodes.Stloc, tmp);
                    ec.Emit(OpCodes.Ldloca, tmp);
                    ec.FreeTemporaryLocal(tmp, unwrap.Type);
                }
                else if (!conditional_access_dup)
                {
                    instance.Emit(ec);
                }
            }
        }
Exemple #31
0
		public void EmitAssign (EmitContext ec, Expression source)
		{
			ILGenerator ig = ec.ig;
			VariableInfo vi = VariableInfo;

			vi.Assigned = true;

			source.Emit (ec);
			
			ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
		}