DefineLabel() public method

public DefineLabel ( ) : Label
return System.Reflection.Emit.Label
Ejemplo n.º 1
0
        //
        // Called back from YieldStatement
        //
        public virtual void InjectYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
        {
            //
            // Guard against being disposed meantime
            //
            Label disposed = ec.DefineLabel();
            var   iterator = storey as IteratorStorey;

            if (iterator != null)
            {
                ec.EmitThis();
                ec.Emit(OpCodes.Ldfld, iterator.DisposingField.Spec);
                ec.Emit(OpCodes.Brtrue_S, disposed);
            }

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

            if (iterator != null)
            {
                ec.MarkLabel(disposed);
            }

            // mark finally blocks as disabled
            if (unwind_protect && skip_finally != null)
            {
                ec.EmitInt(1);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }
        }
        void EmitMoveNext_NoResumePoints(EmitContext ec)
        {
            ec.EmitThis();
            ec.Emit(OpCodes.Ldfld, storey.PC.Spec);

            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            // We only care if the PC is zero (start executing) or non-zero (don't do anything)
            ec.Emit(OpCodes.Brtrue, move_next_error);

            iterator_body_end = ec.DefineLabel();

            block.EmitEmbedded(ec);

            ec.MarkLabel(iterator_body_end);

            EmitMoveNextEpilogue(ec);

            ec.MarkLabel(move_next_error);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(0);
                ec.Emit(OpCodes.Ret);
            }
        }
Ejemplo n.º 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);

                    var m = ec.Module.PredefinedMembers.InterlockedCompareExchange.Resolve(loc);

                    if (m != null)
                    {
                        ec.Emit(OpCodes.Call, m);
                    }

                    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);
                }
Ejemplo n.º 4
0
        //
        // Called back from YieldStatement
        //
        public virtual void InjectYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
        {
            //
            // Guard against being disposed meantime
            //
            Label disposed = ec.DefineLabel();

            ec.Emit(OpCodes.Ldarg_0);
            ec.Emit(OpCodes.Ldfld, storey.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, storey.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);
        }
Ejemplo n.º 5
0
        public void EmitAwaitOnCompletedDynamic(EmitContext ec, FieldExpr awaiter)
        {
            var critical = Module.PredefinedTypes.ICriticalNotifyCompletion;

            if (!critical.Define())
            {
                throw new NotImplementedException();
            }

            var temp_critical  = new LocalTemporary(critical.TypeSpec);
            var label_critical = ec.DefineLabel();
            var label_end      = ec.DefineLabel();

            //
            // Special path for dynamic awaiters
            //
            // var awaiter = this.$awaiter as ICriticalNotifyCompletion;
            // if (awaiter == null) {
            //    var completion = (INotifyCompletion) this.$awaiter;
            //    this.$builder.AwaitOnCompleted (ref completion, ref this);
            // } else {
            //    this.$builder.AwaitUnsafeOnCompleted (ref awaiter, ref this);
            // }
            //
            awaiter.Emit(ec);
            ec.Emit(OpCodes.Isinst, critical.TypeSpec);
            temp_critical.Store(ec);
            temp_critical.Emit(ec);
            ec.Emit(OpCodes.Brtrue_S, label_critical);

            var temp = new LocalTemporary(Module.PredefinedTypes.INotifyCompletion.TypeSpec);

            awaiter.Emit(ec);
            ec.Emit(OpCodes.Castclass, temp.Type);
            temp.Store(ec);
            EmitOnCompleted(ec, temp, false);
            temp.Release(ec);
            ec.Emit(OpCodes.Br_S, label_end);

            ec.MarkLabel(label_critical);

            EmitOnCompleted(ec, temp_critical, true);

            ec.MarkLabel(label_end);

            temp_critical.Release(ec);
        }
Ejemplo n.º 6
0
        public void EmitDispose(EmitContext ec)
        {
            Label end = ec.DefineLabel();

            Label [] labels          = null;
            int      n_resume_points = resume_points == null ? 0 : resume_points.Count;

            for (int i = 0; i < n_resume_points; ++i)
            {
                ResumableStatement s = resume_points [i];
                Label ret            = s.PrepareForDispose(ec, end);
                if (ret.Equals(end) && labels == null)
                {
                    continue;
                }
                if (labels == null)
                {
                    labels = new Label [resume_points.Count + 1];
                    for (int j = 0; j <= i; ++j)
                    {
                        labels [j] = end;
                    }
                }

                labels [i + 1] = ret;
            }

            if (labels != null)
            {
                current_pc = ec.GetTemporaryLocal(ec.BuiltinTypes.UInt);
                ec.Emit(OpCodes.Ldarg_0);
                ec.Emit(OpCodes.Ldfld, IteratorHost.PC.Spec);
                ec.Emit(OpCodes.Stloc, current_pc);
            }

            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt(1);
            ec.Emit(OpCodes.Stfld, IteratorHost.DisposingField.Spec);

            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt((int)State.After);
            ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec);

            if (labels != null)
            {
                //SymbolWriter.StartIteratorDispatcher (ec.ig);
                ec.Emit(OpCodes.Ldloc, current_pc);
                ec.Emit(OpCodes.Switch, labels);
                //SymbolWriter.EndIteratorDispatcher (ec.ig);

                foreach (ResumableStatement s in resume_points)
                {
                    s.EmitForDispose(ec, this, end, true);
                }
            }

            ec.MarkLabel(end);
        }
Ejemplo n.º 7
0
        protected void EmitConditionalAccess(EmitContext ec)
        {
            var a_expr = arguments [0].Expr;

            var des = a_expr as DynamicExpressionStatement;

            if (des != null)
            {
                des.EmitConditionalAccess(ec);
            }

            if (HasConditionalAccess())
            {
                var NullOperatorLabel = ec.DefineLabel();

                if (ExpressionAnalyzer.IsInexpensiveLoad(a_expr))
                {
                    a_expr.Emit(ec);
                }
                else
                {
                    var lt = new LocalTemporary(a_expr.Type);
                    lt.EmitAssign(ec, a_expr, true, false);

                    Arguments [0].Expr = lt;
                }

                ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);

                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);

                return;
            }

            if (a_expr.HasConditionalAccess())
            {
                var lt = new LocalTemporary(a_expr.Type);
                lt.EmitAssign(ec, a_expr, false, false);

                Arguments [0].Expr = lt;
            }
        }
Ejemplo n.º 8
0
        public void EmitResultLift(EmitContext ec, TypeSpec type, bool statement)
        {
            if (!NullShortCircuit)
            {
                throw new InternalErrorException();
            }

            bool     value_rt = TypeSpec.IsValueType(type);
            TypeSpec lifted;

            if (value_rt)
            {
                if (type.IsNullableType)
                {
                    lifted = type;
                }
                else
                {
                    lifted = Nullable.NullableInfo.MakeType(ec.Module, type);
                    ec.Emit(OpCodes.Newobj, Nullable.NullableInfo.GetConstructor(lifted));
                }
            }
            else
            {
                lifted = null;
            }

            var end = ec.DefineLabel();

            if (value_on_stack || !statement)
            {
                ec.Emit(OpCodes.Br_S, end);
            }

            ec.MarkLabel(NullOperatorLabel);

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

            if (!statement)
            {
                if (value_rt)
                {
                    Nullable.LiftedNull.Create(lifted, Location.Null).Emit(ec);
                }
                else
                {
                    ec.EmitNull();
                }
            }

            ec.MarkLabel(end);
        }
Ejemplo n.º 9
0
		public override void Emit (EmitContext ec)
		{
			Label l_initialized = ec.DefineLabel ();

			if (mg_cache != null) {
				ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
				ec.Emit (OpCodes.Brtrue_S, l_initialized);
			}

			base.Emit (ec);

			if (mg_cache != null) {
				ec.Emit (OpCodes.Stsfld, mg_cache.Spec);
				ec.MarkLabel (l_initialized);
				ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
			}
		}
Ejemplo n.º 10
0
        public Expression EmitContinuationInitialization(EmitContext ec)
        {
            //
            // When more than 1 awaiter has been used in the block we
            // introduce class scope field to cache continuation delegate
            //
            if (awaiters > 1)
            {
                if (continuation == null)
                {
                    continuation = AddCompilerGeneratedField("$continuation", new TypeExpression(action, Location), true);
                    continuation.Define();
                }

                var fexpr = new FieldExpr(continuation, Location);
                fexpr.InstanceExpression = new CompilerGeneratedThis(CurrentType, Location);

                //
                // if ($continuation == null)
                //    $continuation = new Action (MoveNext);
                //
                fexpr.Emit(ec);

                var skip_cont_init = ec.DefineLabel();
                ec.Emit(OpCodes.Brtrue_S, skip_cont_init);

                ec.EmitThis();
                EmitActionLoad(ec);
                ec.Emit(OpCodes.Stfld, continuation.Spec);
                ec.MarkLabel(skip_cont_init);

                return(fexpr);
            }

            //
            // Otherwise simply use temporary local variable
            //
            var field = LocalVariable.CreateCompilerGenerated(action, OriginalSourceBlock, Location);

            EmitActionLoad(ec);
            field.EmitAssign(ec);
            return(new LocalVariableReference(field, Location));
        }
Ejemplo n.º 11
0
        void EmitMoveNext_NoResumePoints(EmitContext ec)
        {
            ec.EmitThis();
            ec.Emit(OpCodes.Ldfld, storey.PC.Spec);

            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            // We only care if the PC is zero (start executing) or non-zero (don't do anything)
            ec.Emit(OpCodes.Brtrue, move_next_error);

            BodyEnd = ec.DefineLabel();

            var async_init = this as AsyncInitializer;

            if (async_init != null)
            {
                ec.BeginExceptionBlock();
            }

            block.EmitEmbedded(ec);

            if (async_init != null)
            {
                async_init.EmitCatchBlock(ec);
            }

            ec.MarkLabel(BodyEnd);

            EmitMoveNextEpilogue(ec);

            ec.MarkLabel(move_next_error);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(0);
                ec.Emit(OpCodes.Ret);
            }

            ec.MarkLabel(move_next_ok);
        }
Ejemplo n.º 12
0
        public override void EmitStatement(EmitContext ec)
        {
            if (conditionalAccessReceiver)
            {
                ec.ConditionalAccess = new ConditionalAccessContext(type, ec.DefineLabel())
                {
                    Statement = true
                };
            }

            var call = new CallEmitter();

            call.InstanceExpression = InstanceExpr;
            call.EmitStatement(ec, method, arguments, loc);

            if (conditionalAccessReceiver)
            {
                ec.CloseConditionalAccess(null);
            }
        }
Ejemplo n.º 13
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);
                }
Ejemplo n.º 14
0
        public override void Emit(EmitContext ec)
        {
            if (conditionalAccessReceiver)
            {
                ec.ConditionalAccess = new ConditionalAccessContext(type, ec.DefineLabel());
            }

            //
            // Invocation on delegates call the virtual Invoke member
            // so we are always `instance' calls
            //
            var call = new CallEmitter();

            call.InstanceExpression = InstanceExpr;
            call.Emit(ec, method, arguments, loc);

            if (conditionalAccessReceiver)
            {
                ec.CloseConditionalAccess(type.IsNullableType && type != method.ReturnType ? type : null);
            }
        }
Ejemplo n.º 15
0
        public void Emit(EmitContext ec)
        {
            Nullable.Unwrap unwrap;

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

            if (unwrap != null)
            {
                unwrap.Store(ec);
                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brfalse, NullOperatorLabel);
                unwrap.Emit(ec);
                var tmp = ec.GetTemporaryLocal(unwrap.Type);
                ec.Emit(OpCodes.Stloc, tmp);
                ec.Emit(OpCodes.Ldloca, tmp);
                ec.FreeTemporaryLocal(tmp, unwrap.Type);
                return;
            }

            EmitLoad(ec);

            if (NullShortCircuit)
            {
                ec.Emit(OpCodes.Dup);
                ec.Emit(OpCodes.Brfalse, NullOperatorLabel);
            }

            value_on_stack = true;
        }
Ejemplo n.º 16
0
        public override void Emit(EmitContext ec)
        {
            if (conditional_access_receiver)
            {
                ec.ConditionalAccess = new ConditionalAccessContext(type, ec.DefineLabel());
            }

            if (method_group.InstanceExpression == null)
            {
                ec.EmitNull();
            }
            else
            {
                var ie = new InstanceEmitter(method_group.InstanceExpression, false);
                ie.Emit(ec, method_group.ConditionalAccess);
            }

            var delegate_method = method_group.BestCandidate;

            // Any delegate must be sealed
            if (!delegate_method.DeclaringType.IsDelegate && delegate_method.IsVirtual && !method_group.IsBase)
            {
                ec.Emit(OpCodes.Dup);
                ec.Emit(OpCodes.Ldvirtftn, delegate_method);
            }
            else
            {
                ec.Emit(OpCodes.Ldftn, delegate_method);
            }

            ec.Emit(OpCodes.Newobj, constructor_method);

            if (conditional_access_receiver)
            {
                ec.CloseConditionalAccess(null);
            }
        }
Ejemplo n.º 17
0
		public override void Emit (EmitContext ec)
		{
			if (conditionalAccessReceiver) {
				ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
			}

			//
			// Invocation on delegates call the virtual Invoke member
			// so we are always `instance' calls
			//
			var call = new CallEmitter ();
			call.InstanceExpression = InstanceExpr;
			call.Emit (ec, method, arguments, loc);

			if (conditionalAccessReceiver)
				ec.CloseConditionalAccess (type.IsNullableType && type !=  method.ReturnType ? type : null);
		}
Ejemplo n.º 18
0
		public override void Emit (EmitContext ec)
		{
			if (conditional_access_receiver)
				ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());

			if (method_group.InstanceExpression == null) {
				ec.EmitNull ();
			} else {
				var ie = new InstanceEmitter (method_group.InstanceExpression, false);
				ie.Emit (ec, method_group.ConditionalAccess);
			}

			var delegate_method = method_group.BestCandidate;

			// Any delegate must be sealed
			if (!delegate_method.DeclaringType.IsDelegate && delegate_method.IsVirtual && !method_group.IsBase) {
				ec.Emit (OpCodes.Dup);
				ec.Emit (OpCodes.Ldvirtftn, delegate_method);
			} else {
				ec.Emit (OpCodes.Ldftn, delegate_method);
			}

			ec.Emit (OpCodes.Newobj, constructor_method);

			if (conditional_access_receiver)
				ec.CloseConditionalAccess (null);
		}
Ejemplo n.º 19
0
		protected void EmitConditionalAccess (EmitContext ec)
		{
			var a_expr = arguments [0].Expr;

			var des = a_expr as DynamicExpressionStatement;
			if (des != null) {
				des.EmitConditionalAccess (ec);
			}

			if (HasConditionalAccess ()) {
				var NullOperatorLabel = ec.DefineLabel ();

				if (ExpressionAnalyzer.IsInexpensiveLoad (a_expr)) {
					a_expr.Emit (ec);
				} else {
					var lt = new LocalTemporary (a_expr.Type);
					lt.EmitAssign (ec, a_expr, true, false);

					Arguments [0].Expr = lt;
				}

				ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);

				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);

				return;
			}

			if (a_expr.HasConditionalAccess ()) {
				var lt = new LocalTemporary (a_expr.Type);
				lt.EmitAssign (ec, a_expr, false, false);

				Arguments [0].Expr = lt;
			}
		}
Ejemplo n.º 20
0
		protected override void DoEmit (EmitContext ec)
		{
			Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
			ec.LoopBegin = ec.DefineLabel ();
			ec.LoopEnd = ec.DefineLabel ();

			statement.Emit (ec);

			ec.LoopBegin = old_begin;
			ec.LoopEnd = old_end;
		}
Ejemplo n.º 21
0
			protected override void DoEmit (EmitContext ec)
			{
				copy.EmitAssign (ec, for_each.expr);

				int rank = length_exprs.Length;
				Label[] test = new Label [rank];
				Label[] loop = new Label [rank];

				for (int i = 0; i < rank; i++) {
					test [i] = ec.DefineLabel ();
					loop [i] = ec.DefineLabel ();

					if (lengths != null)
						lengths [i].EmitAssign (ec, length_exprs [i]);
				}

				IntConstant zero = new IntConstant (0, loc);
				for (int i = 0; i < rank; i++) {
					variables [i].EmitAssign (ec, zero);

					ec.Emit (OpCodes.Br, test [i]);
					ec.MarkLabel (loop [i]);
				}

				variable.local_info.CreateBuilder (ec);
				variable.EmitAssign (ec, conv, false, false);

				statement.Emit (ec);

				ec.MarkLabel (ec.LoopBegin);

				for (int i = rank - 1; i >= 0; i--){
					counter [i].Emit (ec);

					ec.MarkLabel (test [i]);
					variables [i].Emit (ec);

					if (lengths != null)
						lengths [i].Emit (ec);
					else
						length_exprs [i].Emit (ec);

					ec.Emit (OpCodes.Blt, loop [i]);
				}

				ec.MarkLabel (ec.LoopEnd);
			}
Ejemplo n.º 22
0
		public override Label PrepareForDispose (EmitContext ec, Label end)
		{
			if (!prepared_for_dispose) {
				prepared_for_dispose = true;
				dispose_try_block = ec.DefineLabel ();
			}
			return dispose_try_block;
		}
Ejemplo n.º 23
0
		public override void Emit (EmitContext ec)
		{
			if (Report.Errors > 0)
				return;

#if PRODUCTION
			try {
#endif
			if (ec.HasReturnLabel)
				ec.ReturnLabel = ec.DefineLabel ();

			base.Emit (ec);

			ec.Mark (EndLocation);

			if (ec.HasReturnLabel)
				ec.MarkLabel (ec.ReturnLabel);

			if (ec.return_value != null) {
				ec.Emit (OpCodes.Ldloc, ec.return_value);
				ec.Emit (OpCodes.Ret);
			} else {
				//
				// If `HasReturnLabel' is set, then we already emitted a
				// jump to the end of the method, so we must emit a `ret'
				// there.
				//
				// Unfortunately, System.Reflection.Emit automatically emits
				// a leave to the end of a finally block.  This is a problem
				// if no code is following the try/finally block since we may
				// jump to a point after the end of the method.
				// As a workaround, we're always creating a return label in
				// this case.
				//

				if (ec.HasReturnLabel || !unreachable) {
					if (ec.ReturnType != TypeManager.void_type)
						ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
					ec.Emit (OpCodes.Ret);
				}
			}

#if PRODUCTION
			} catch (Exception e){
				Console.WriteLine ("Exception caught by the compiler while emitting:");
				Console.WriteLine ("   Block that caused the problem begin at: " + block.loc);
					
				Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
				throw;
			}
#endif
		}
Ejemplo n.º 24
0
		protected override void DoEmit (EmitContext ec)
		{
			Label false_target = ec.DefineLabel ();
			Label end;

			//
			// If we're a boolean constant, Resolve() already
			// eliminated dead code for us.
			//
			Constant c = expr as Constant;
			if (c != null){
				c.EmitSideEffect (ec);

				if (!c.IsDefaultValue)
					TrueStatement.Emit (ec);
				else if (FalseStatement != null)
					FalseStatement.Emit (ec);

				return;
			}			
			
			expr.EmitBranchable (ec, false_target, false);
			
			TrueStatement.Emit (ec);

			if (FalseStatement != null){
				bool branch_emitted = false;
				
				end = ec.DefineLabel ();
				if (!is_true_ret){
					ec.Emit (OpCodes.Br, end);
					branch_emitted = true;
				}

				ec.MarkLabel (false_target);
				FalseStatement.Emit (ec);

				if (branch_emitted)
					ec.MarkLabel (end);
			} else {
				ec.MarkLabel (false_target);
			}
		}
Ejemplo n.º 25
0
				protected override void EmitFinallyBody (EmitContext ec)
				{
					Label call_dispose = ec.DefineLabel ();
					if (dispose != null) {
						local_copy.Emit (ec, false);
						ec.Emit (OpCodes.Isinst, dispose.Type);
						dispose.Store (ec);
					}

					base.EmitFinallyBody (ec);

					if (dispose != null) {
						ec.MarkLabel (call_dispose);
						dispose.Release (ec);
					}
				}
Ejemplo n.º 26
0
        void EmitMoveNext(EmitContext ec)
        {
            move_next_ok    = ec.DefineLabel();
            move_next_error = ec.DefineLabel();

            if (resume_points == null)
            {
                EmitMoveNext_NoResumePoints(ec, block);
                return;
            }

            current_pc = ec.GetTemporaryLocal(ec.BuiltinTypes.UInt);
            ec.Emit(OpCodes.Ldarg_0);
            ec.Emit(OpCodes.Ldfld, IteratorHost.PC.Spec);
            ec.Emit(OpCodes.Stloc, current_pc);

            // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt((int)State.After);
            ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec);

            Label [] labels = new Label [1 + resume_points.Count];
            labels [0] = ec.DefineLabel();

            bool need_skip_finally = false;

            for (int i = 0; i < resume_points.Count; ++i)
            {
                ResumableStatement s = resume_points [i];
                need_skip_finally |= s is ExceptionStatement;
                labels [i + 1]     = s.PrepareForEmit(ec);
            }

            if (need_skip_finally)
            {
                skip_finally = ec.GetTemporaryLocal(ec.BuiltinTypes.Bool);
                ec.Emit(OpCodes.Ldc_I4_0);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }

            SymbolWriter.StartIteratorDispatcher(ec);
            ec.Emit(OpCodes.Ldloc, current_pc);
            ec.Emit(OpCodes.Switch, labels);

            ec.Emit(OpCodes.Br, move_next_error);
            SymbolWriter.EndIteratorDispatcher(ec);

            ec.MarkLabel(labels [0]);

            SymbolWriter.StartIteratorBody(ec);
            block.Emit(ec);
            SymbolWriter.EndIteratorBody(ec);

            SymbolWriter.StartIteratorDispatcher(ec);

            ec.Emit(OpCodes.Ldarg_0);
            ec.EmitInt((int)State.After);
            ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec);

            ec.MarkLabel(move_next_error);
            ec.EmitInt(0);
            ec.Emit(OpCodes.Ret);

            ec.MarkLabel(move_next_ok);
            ec.Emit(OpCodes.Ldc_I4_1);
            ec.Emit(OpCodes.Ret);

            SymbolWriter.EndIteratorDispatcher(ec);
        }
Ejemplo n.º 27
0
        public void EmitPrologue(EmitContext ec)
        {
            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            //
            // awaiter = expr.GetAwaiter ();
            //
            fe_awaiter.EmitAssign(ec, expr, false, false);

            Label skip_continuation = ec.DefineLabel();

            is_completed.InstanceExpression = fe_awaiter;
            is_completed.EmitBranchable(ec, skip_continuation, true);

            base.DoEmit(ec);

            FieldSpec[] stack_fields = null;
            TypeSpec[]  stack        = null;
            //
            // Here is the clever bit. We know that await statement has to yield the control
            // back but it can appear inside almost any expression. This means the stack can
            // contain any depth of values and same values have to be present when the continuation
            // handles control back.
            //
            // For example: await a + await b
            //
            // In this case we fabricate a static stack forwarding method which moves the values
            // from the stack to async storey fields. On re-entry point we restore exactly same
            // stack using these fields.
            //
            // We fabricate a static method because we don't want to touch original stack and
            // the instance method would require `this' as the first stack value on the stack
            //
            if (ec.StackHeight > 0)
            {
                var async_storey = (AsyncTaskStorey)machine_initializer.Storey;

                stack = ec.GetStackTypes();
                var method = async_storey.GetStackForwarder(stack, out stack_fields);
                ec.EmitThis();
                ec.Emit(OpCodes.Call, method);
            }

            var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);

            mg_completed.InstanceExpression = fe_awaiter;

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            //
            // awaiter.OnCompleted (continuation);
            //
            mg_completed.EmitCall(ec, args);

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);

            if (stack_fields != null)
            {
                for (int i = 0; i < stack_fields.Length; ++i)
                {
                    ec.EmitThis();

                    var field = stack_fields[i];

                    //
                    // We don't store `this' because it can be easily re-created
                    //
                    if (field == null)
                    {
                        continue;
                    }

                    if (stack[i] is ReferenceContainer)
                    {
                        ec.Emit(OpCodes.Ldflda, field);
                    }
                    else
                    {
                        ec.Emit(OpCodes.Ldfld, field);
                    }
                }
            }

            ec.MarkLabel(skip_continuation);
        }
Ejemplo n.º 28
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);
				}
			}
		}
Ejemplo n.º 29
0
		public Label GetILLabel (EmitContext ec)
		{
			if (!il_label_set){
				il_label = ec.DefineLabel ();
				il_label_set = true;
			}
			return il_label;
		}
Ejemplo n.º 30
0
        void EmitMoveNext(EmitContext ec)
        {
            move_next_ok    = ec.DefineLabel();
            move_next_error = ec.DefineLabel();

            if (resume_points == null)
            {
                EmitMoveNext_NoResumePoints(ec);
                return;
            }

            current_pc = ec.GetTemporaryLocal(ec.BuiltinTypes.UInt);
            ec.EmitThis();
            ec.Emit(OpCodes.Ldfld, storey.PC.Spec);
            ec.Emit(OpCodes.Stloc, current_pc);

            // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            Label[] labels = new Label[1 + resume_points.Count];
            labels[0] = ec.DefineLabel();

            bool need_skip_finally = false;

            for (int i = 0; i < resume_points.Count; ++i)
            {
                ResumableStatement s = resume_points[i];
                need_skip_finally |= s is ExceptionStatement;
                labels[i + 1]      = s.PrepareForEmit(ec);
            }

            if (need_skip_finally)
            {
                skip_finally = ec.GetTemporaryLocal(ec.BuiltinTypes.Bool);
                ec.EmitInt(0);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }

            var async_init = this as AsyncInitializer;

            if (async_init != null)
            {
                ec.BeginExceptionBlock();
            }

            ec.Emit(OpCodes.Ldloc, current_pc);
            ec.Emit(OpCodes.Switch, labels);

            ec.Emit(async_init != null ? OpCodes.Leave : OpCodes.Br, move_next_error);

            ec.MarkLabel(labels[0]);

            BodyEnd = ec.DefineLabel();

            block.EmitEmbedded(ec);

            ec.MarkLabel(BodyEnd);

            if (async_init != null)
            {
                async_init.EmitCatchBlock(ec);
            }

            ec.Mark(Block.Original.EndLocation);
            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            EmitMoveNextEpilogue(ec);

            ec.MarkLabel(move_next_error);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(0);
                ec.Emit(OpCodes.Ret);
            }

            ec.MarkLabel(move_next_ok);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(1);
                ec.Emit(OpCodes.Ret);
            }
        }
Ejemplo n.º 31
0
		public Label GetILLabelCode (EmitContext ec)
		{
			if (!il_label_code_set){
				il_label_code = ec.DefineLabel ();
				il_label_code_set = true;
			}
			return il_label_code;
		}				
Ejemplo n.º 32
0
		public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
		{
			if (emitted_dispose)
				return;

			emitted_dispose = true;

			Label end_of_try = ec.DefineLabel ();

			// Ensure that the only way we can get into this code is through a dispatcher
			if (have_dispatcher)
				ec.Emit (OpCodes.Br, end);

			ec.BeginExceptionBlock ();

			ec.MarkLabel (dispose_try_block);

			Label [] labels = null;
			for (int i = 0; i < resume_points.Count; ++i) {
				ResumableStatement s = (ResumableStatement) resume_points [i];
				Label ret = s.PrepareForDispose (ec, end_of_try);
				if (ret.Equals (end_of_try) && labels == null)
					continue;
				if (labels == null) {
					labels = new Label [resume_points.Count];
					for (int j = 0; j < i; ++j)
						labels [j] = end_of_try;
				}
				labels [i] = ret;
			}

			if (labels != null) {
				int j;
				for (j = 1; j < labels.Length; ++j)
					if (!labels [0].Equals (labels [j]))
						break;
				bool emit_dispatcher = j < labels.Length;

				if (emit_dispatcher) {
					//SymbolWriter.StartIteratorDispatcher (ec.ig);
					ec.Emit (OpCodes.Ldloc, iterator.CurrentPC);
					ec.EmitInt (first_resume_pc);
					ec.Emit (OpCodes.Sub);
					ec.Emit (OpCodes.Switch, labels);
					//SymbolWriter.EndIteratorDispatcher (ec.ig);
				}

				foreach (ResumableStatement s in resume_points)
					s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
			}

			ec.MarkLabel (end_of_try);

			ec.BeginFinallyBlock ();

			EmitFinallyBody (ec);

			ec.EndExceptionBlock ();
		}
Ejemplo n.º 33
0
		protected override void DoEmit (EmitContext ec)
		{
			Label loop = ec.DefineLabel ();
			Label old_begin = ec.LoopBegin;
			Label old_end = ec.LoopEnd;
			
			ec.LoopBegin = ec.DefineLabel ();
			ec.LoopEnd = ec.DefineLabel ();
				
			ec.MarkLabel (loop);
			EmbeddedStatement.Emit (ec);
			ec.MarkLabel (ec.LoopBegin);

			//
			// Dead code elimination
			//
			if (expr is Constant){
				bool res = !((Constant) expr).IsDefaultValue;

				expr.EmitSideEffect (ec);
				if (res)
					ec.Emit (OpCodes.Br, loop); 
			} else
				expr.EmitBranchable (ec, loop, true);
			
			ec.MarkLabel (ec.LoopEnd);

			ec.LoopBegin = old_begin;
			ec.LoopEnd = old_end;
		}
Ejemplo n.º 34
0
		protected override void DoEmit (EmitContext ec)
		{
			if (InitStatement != null)
				InitStatement.Emit (ec);

			if (empty) {
				Test.EmitSideEffect (ec);
				return;
			}

			Label old_begin = ec.LoopBegin;
			Label old_end = ec.LoopEnd;
			Label loop = ec.DefineLabel ();
			Label test = ec.DefineLabel ();

			ec.LoopBegin = ec.DefineLabel ();
			ec.LoopEnd = ec.DefineLabel ();

			ec.Emit (OpCodes.Br, test);
			ec.MarkLabel (loop);
			Statement.Emit (ec);

			ec.MarkLabel (ec.LoopBegin);
			Increment.Emit (ec);

			ec.MarkLabel (test);
			//
			// If test is null, there is no test, and we are just
			// an infinite loop
			//
			if (Test != null){
				//
				// The Resolve code already catches the case for
				// Test == Constant (false) so we know that
				// this is true
				//
				if (Test is Constant) {
					Test.EmitSideEffect (ec);
					ec.Emit (OpCodes.Br, loop);
				} else {
					Test.EmitBranchable (ec, loop, true);
				}
				
			} else
				ec.Emit (OpCodes.Br, loop);
			ec.MarkLabel (ec.LoopEnd);

			ec.LoopBegin = old_begin;
			ec.LoopEnd = old_end;
		}
Ejemplo n.º 35
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);
		}
Ejemplo n.º 36
0
		public Label LabelTarget (EmitContext ec)
		{
			if (defined)
				return label;

			label = ec.DefineLabel ();
			defined = true;
			return label;
		}
Ejemplo n.º 37
0
		protected override void EmitFinallyBody (EmitContext ec)
		{
			Label skip = ec.DefineLabel ();

			bool emit_null_check = !TypeManager.IsValueType (var.Type);
			if (emit_null_check) {
				var.Emit (ec);
				ec.Emit (OpCodes.Brfalse, skip);
			}

			Invocation.EmitCall (ec, var, TypeManager.void_dispose_void, null, loc);

			if (emit_null_check)
				ec.MarkLabel (skip);
		}
Ejemplo n.º 38
0
        public void EmitPrologue(EmitContext ec)
        {
            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            //
            // awaiter = expr.GetAwaiter ();
            //
            fe_awaiter.EmitAssign(ec, expr, false, false);

            Label skip_continuation = ec.DefineLabel();

            Expression completed_expr;

            if (IsDynamic)
            {
                var rc = new ResolveContext(ec.MemberContext);

                Arguments dargs = new Arguments(1);
                dargs.Add(new Argument(fe_awaiter));
                completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc);
            }
            else
            {
                var pe = PropertyExpr.CreatePredefined(is_completed, loc);
                pe.InstanceExpression = fe_awaiter;
                completed_expr        = pe;
            }

            completed_expr.EmitBranchable(ec, skip_continuation, true);

            base.DoEmit(ec);

            //
            // The stack has to be empty before calling await continuation. We handle this
            // by lifting values which would be left on stack into class fields. The process
            // is quite complicated and quite hard to test because any expression can possibly
            // leave a value on the stack.
            //
            // Following assert fails when some of expression called before is missing EmitToField
            // or parent expression fails to find await in children expressions
            //
            ec.AssertEmptyStack();

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            if (IsDynamic)
            {
                var rc      = new ResolveContext(ec.MemberContext);
                var mg_expr = new Invocation(new MemberAccess(fe_awaiter, "OnCompleted"), args).Resolve(rc);

                ExpressionStatement es = (ExpressionStatement)mg_expr;
                es.EmitStatement(ec);
            }
            else
            {
                var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);
                mg_completed.InstanceExpression = fe_awaiter;

                //
                // awaiter.OnCompleted (continuation);
                //
                mg_completed.EmitCall(ec, args);
            }

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);
            ec.MarkLabel(skip_continuation);
        }
Ejemplo n.º 39
0
        internal void EmitMoveNext(EmitContext ec, Block original_block)
        {
            move_next_ok = ec.DefineLabel ();
            move_next_error = ec.DefineLabel ();

            if (resume_points == null) {
                EmitMoveNext_NoResumePoints (ec, original_block);
                return;
            }

            current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
            ec.Emit (OpCodes.Ldarg_0);
            ec.Emit (OpCodes.Ldfld, IteratorHost.PC.Spec);
            ec.Emit (OpCodes.Stloc, current_pc);

            // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
            ec.Emit (OpCodes.Ldarg_0);
            ec.EmitInt ((int) State.After);
            ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec);

            Label [] labels = new Label [1 + resume_points.Count];
            labels [0] = ec.DefineLabel ();

            bool need_skip_finally = false;
            for (int i = 0; i < resume_points.Count; ++i) {
                ResumableStatement s = resume_points [i];
                need_skip_finally |= s is ExceptionStatement;
                labels [i+1] = s.PrepareForEmit (ec);
            }

            if (need_skip_finally) {
                skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
                ec.Emit (OpCodes.Ldc_I4_0);
                ec.Emit (OpCodes.Stloc, skip_finally);
            }

            SymbolWriter.StartIteratorDispatcher (ec);
            ec.Emit (OpCodes.Ldloc, current_pc);
            ec.Emit (OpCodes.Switch, labels);

            ec.Emit (OpCodes.Br, move_next_error);
            SymbolWriter.EndIteratorDispatcher (ec);

            ec.MarkLabel (labels [0]);

            SymbolWriter.StartIteratorBody (ec);
            original_block.Emit (ec);
            SymbolWriter.EndIteratorBody (ec);

            SymbolWriter.StartIteratorDispatcher (ec);

            ec.Emit (OpCodes.Ldarg_0);
            ec.EmitInt ((int) State.After);
            ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec);

            ec.MarkLabel (move_next_error);
            ec.EmitInt (0);
            ec.Emit (OpCodes.Ret);

            ec.MarkLabel (move_next_ok);
            ec.Emit (OpCodes.Ldc_I4_1);
            ec.Emit (OpCodes.Ret);

            SymbolWriter.EndIteratorDispatcher (ec);
        }
Ejemplo n.º 40
0
		protected void EmitCall (EmitContext ec, Expression binder, Arguments arguments, bool isStatement)
		{
			//
			// This method generates all internal infrastructure for a dynamic call. The
			// reason why it's quite complicated is the mixture of dynamic and anonymous
			// methods. Dynamic itself requires a temporary class (ContainerX) and anonymous
			// methods can generate temporary storey as well (AnonStorey). Handling MVAR
			// type parameters rewrite is non-trivial in such case as there are various
			// combinations possible therefore the mutator is not straightforward. Secondly
			// we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit
			// correct Site field type and its access from EmitContext.
			//

			int dyn_args_count = arguments == null ? 0 : arguments.Count;
			int default_args = isStatement ? 1 : 2;
			var module = ec.Module;

			bool has_ref_out_argument = false;
			var targs = new TypeExpression[dyn_args_count + default_args];
			targs[0] = new TypeExpression (module.PredefinedTypes.CallSite.TypeSpec, loc);

			TypeExpression[] targs_for_instance = null;
			TypeParameterMutator mutator;

			var site_container = ec.CreateDynamicSite ();

			if (context_mvars != null) {
				TypeParameters tparam;
				TypeContainer sc = site_container;
				do {
					tparam = sc.CurrentTypeParameters;
					sc = sc.Parent;
				} while (tparam == null);

				mutator = new TypeParameterMutator (context_mvars, tparam);

				if (!ec.IsAnonymousStoreyMutateRequired) {
					targs_for_instance = new TypeExpression[targs.Length];
					targs_for_instance[0] = targs[0];
				}
			} else {
				mutator = null;
			}

			for (int i = 0; i < dyn_args_count; ++i) {
				Argument a = arguments[i];
				if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
					has_ref_out_argument = true;

				var t = a.Type;

				// Convert any internal type like dynamic or null to object
				if (t.Kind == MemberKind.InternalCompilerType)
					t = ec.BuiltinTypes.Object;

				if (targs_for_instance != null)
					targs_for_instance[i + 1] = new TypeExpression (t, loc);

				if (mutator != null)
					t = t.Mutate (mutator);

				targs[i + 1] = new TypeExpression (t, loc);
			}

			TypeExpr del_type = null;
			TypeExpr del_type_instance_access = null;
			if (!has_ref_out_argument) {
				string d_name = isStatement ? "Action" : "Func";

				TypeSpec te = null;
				Namespace type_ns = module.GlobalRootNamespace.GetNamespace ("System", true);
				if (type_ns != null) {
					te = type_ns.LookupType (module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc);
				}

				if (te != null) {
					if (!isStatement) {
						var t = type;
						if (t.Kind == MemberKind.InternalCompilerType)
							t = ec.BuiltinTypes.Object;

						if (targs_for_instance != null)
							targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression (t, loc);

						if (mutator != null)
							t = t.Mutate (mutator);

						targs[targs.Length - 1] = new TypeExpression (t, loc);
					}

					del_type = new GenericTypeExpr (te, new TypeArguments (targs), loc);
					if (targs_for_instance != null)
						del_type_instance_access = new GenericTypeExpr (te, new TypeArguments (targs_for_instance), loc);
					else
						del_type_instance_access = del_type;
				}
			}

			//
			// Create custom delegate when no appropriate predefined delegate has been found
			//
			Delegate d;
			if (del_type == null) {
				TypeSpec rt = isStatement ? ec.BuiltinTypes.Void : type;
				Parameter[] p = new Parameter[dyn_args_count + 1];
				p[0] = new Parameter (targs[0], "p0", Parameter.Modifier.NONE, null, loc);

				var site = ec.CreateDynamicSite ();
				int index = site.Containers == null ? 0 : site.Containers.Count;

				if (mutator != null)
					rt = mutator.Mutate (rt);

				for (int i = 1; i < dyn_args_count + 1; ++i) {
					p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc);
				}

				d = new Delegate (site, new TypeExpression (rt, loc),
					Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
					new MemberName ("Container" + index.ToString ("X")),
					new ParametersCompiled (p), null);

				d.CreateContainer ();
				d.DefineContainer ();
				d.Define ();
				d.PrepareEmit ();

				site.AddTypeContainer (d);

				//
				// Add new container to inflated site container when the
				// member cache already exists
				//
				if (site.CurrentType is InflatedTypeSpec && index > 0)
					site.CurrentType.MemberCache.AddMember (d.CurrentType);

				del_type = new TypeExpression (d.CurrentType, loc);
				if (targs_for_instance != null) {
					del_type_instance_access = null;
				} else {
					del_type_instance_access = del_type;
				}
			} else {
				d = null;
			}

			var site_type_decl = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type), loc);
			var field = site_container.CreateCallSiteField (site_type_decl, loc);
			if (field == null)
				return;

			if (del_type_instance_access == null) {
				var dt = d.CurrentType.DeclaringType.MakeGenericType (module, context_mvars.Types);
				del_type_instance_access = new TypeExpression (MemberCache.GetMember (dt, d.CurrentType), loc);
			}

			var instanceAccessExprType = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec,
				new TypeArguments (del_type_instance_access), loc);

			if (instanceAccessExprType.ResolveAsType (ec.MemberContext) == null)
				return;

			bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired;

			TypeSpec gt;
			if (inflate_using_mvar || context_mvars == null) {
				gt = site_container.CurrentType;
			} else {
				gt = site_container.CurrentType.MakeGenericType (module, context_mvars.Types);
			}

			// When site container already exists the inflated version has to be
			// updated manually to contain newly created field
			if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) {
				var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes;
				var inflator = new TypeParameterInflator (module, gt, tparams, gt.TypeArguments);
				gt.MemberCache.AddMember (field.InflateMember (inflator));
			}

			FieldExpr site_field_expr = new FieldExpr (MemberCache.GetMember (gt, field), loc);

			BlockContext bc = new BlockContext (ec.MemberContext, null, ec.BuiltinTypes.Void);

			Arguments args = new Arguments (1);
			args.Add (new Argument (binder));
			StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (instanceAccessExprType, "Create"), args)));

			using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {

				var conditionalAccessReceiver = IsConditionalAccessReceiver;
				var ca = ec.ConditionalAccess;

				if (conditionalAccessReceiver) {
					ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ()) {
						Statement = isStatement
					};

					//
					// Emit conditional access expressions before dynamic call
					// is initialized. It pushes site_field_expr on stack before
					// the actual instance argument is emited which would cause
					// jump from non-empty stack.
					//
					EmitConditionalAccess (ec);
				}

				if (s.Resolve (bc)) {
					Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc);
					init.Emit (ec);
				}

				args = new Arguments (1 + dyn_args_count);
				args.Add (new Argument (site_field_expr));
				if (arguments != null) {
					int arg_pos = 1;
					foreach (Argument a in arguments) {
						if (a is NamedArgument) {
							// Name is not valid in this context
							args.Add (new Argument (a.Expr, a.ArgType));
						} else {
							args.Add (a);
						}

						if (inflate_using_mvar && a.Type != targs[arg_pos].Type)
							a.Expr.Type = targs[arg_pos].Type;

						++arg_pos;
					}
				}

				var target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (bc), args, false, loc).Resolve (bc);
				if (target != null) {
					target.Emit (ec);
				}

				if (conditionalAccessReceiver) {
					ec.CloseConditionalAccess (!isStatement && type.IsNullableType ? type : null);
					ec.ConditionalAccess = ca;
				}
			}
		}
Ejemplo n.º 41
0
        public void EmitPrologue(EmitContext ec)
        {
            awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(expr.Type);

            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            Label skip_continuation = ec.DefineLabel();

            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                //
                // awaiter = expr.GetAwaiter ();
                //
                fe_awaiter.EmitAssign(ec, expr, false, false);

                Expression completed_expr;
                if (IsDynamic)
                {
                    var rc = new ResolveContext(ec.MemberContext);

                    Arguments dargs = new Arguments(1);
                    dargs.Add(new Argument(fe_awaiter));
                    completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc);

                    dargs = new Arguments(1);
                    dargs.Add(new Argument(completed_expr));
                    completed_expr = new DynamicConversion(ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve(rc);
                }
                else
                {
                    var pe = PropertyExpr.CreatePredefined(awaiter_definition.IsCompleted, loc);
                    pe.InstanceExpression = fe_awaiter;
                    completed_expr        = pe;
                }

                completed_expr.EmitBranchable(ec, skip_continuation, true);
            }

            base.DoEmit(ec);

            //
            // The stack has to be empty before calling await continuation. We handle this
            // by lifting values which would be left on stack into class fields. The process
            // is quite complicated and quite hard to test because any expression can possibly
            // leave a value on the stack.
            //
            // Following assert fails when some of expression called before is missing EmitToField
            // or parent expression fails to find await in children expressions
            //
            ec.AssertEmptyStack();

            var storey = (AsyncTaskStorey)machine_initializer.Storey;

            if (IsDynamic)
            {
                storey.EmitAwaitOnCompletedDynamic(ec, fe_awaiter);
            }
            else
            {
                storey.EmitAwaitOnCompleted(ec, fe_awaiter);
            }

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);
            ec.MarkLabel(skip_continuation);
        }
Ejemplo n.º 42
0
		public override void Emit (EmitContext ec)
		{
			Label l_initialized = ec.DefineLabel ();

			if (mg_cache != null) {
				ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
				ec.Emit (OpCodes.Brtrue_S, l_initialized);
			}

			base.Emit (ec);

			if (mg_cache != null) {
				ec.Emit (OpCodes.Stsfld, mg_cache.Spec);
				ec.MarkLabel (l_initialized);
				ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
			}
		}
Ejemplo n.º 43
0
        void EmitMoveNext(EmitContext ec)
        {
            move_next_ok    = ec.DefineLabel();
            move_next_error = ec.DefineLabel();

            if (resume_points == null)
            {
                EmitMoveNext_NoResumePoints(ec, block);
                return;
            }

            current_pc = ec.GetTemporaryLocal(ec.BuiltinTypes.UInt);
            ec.EmitThis();
            ec.Emit(OpCodes.Ldfld, storey.PC.Spec);
            ec.Emit(OpCodes.Stloc, current_pc);

            // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            Label[] labels = new Label[1 + resume_points.Count];
            labels[0] = ec.DefineLabel();

            bool need_skip_finally = false;

            for (int i = 0; i < resume_points.Count; ++i)
            {
                ResumableStatement s = resume_points[i];
                need_skip_finally |= s is ExceptionStatement;
                labels[i + 1]      = s.PrepareForEmit(ec);
            }

            if (need_skip_finally)
            {
                skip_finally = ec.GetTemporaryLocal(ec.BuiltinTypes.Bool);
                ec.EmitInt(0);
                ec.Emit(OpCodes.Stloc, skip_finally);
            }

            var async_init = this as AsyncInitializer;

            if (async_init != null)
            {
                ec.BeginExceptionBlock();
            }

            SymbolWriter.StartIteratorDispatcher(ec);
            ec.Emit(OpCodes.Ldloc, current_pc);
            ec.Emit(OpCodes.Switch, labels);

            ec.Emit(async_init != null ? OpCodes.Leave : OpCodes.Br, move_next_error);
            SymbolWriter.EndIteratorDispatcher(ec);

            ec.MarkLabel(labels[0]);

            iterator_body_end = ec.DefineLabel();

            SymbolWriter.StartIteratorBody(ec);
            block.Emit(ec);
            SymbolWriter.EndIteratorBody(ec);

            SymbolWriter.StartIteratorDispatcher(ec);

            ec.MarkLabel(iterator_body_end);

            if (async_init != null)
            {
                var catch_value = LocalVariable.CreateCompilerGenerated(ec.Module.Compiler.BuiltinTypes.Exception, block, Location);

                ec.BeginCatchBlock(catch_value.Type);
                catch_value.EmitAssign(ec);

                ec.EmitThis();
                ec.EmitInt((int)IteratorStorey.State.After);
                ec.Emit(OpCodes.Stfld, storey.PC.Spec);

                ((AsyncTaskStorey)async_init.Storey).EmitSetException(ec, new LocalVariableReference(catch_value, Location));

                ec.Emit(OpCodes.Leave, move_next_ok);
                ec.EndExceptionBlock();
            }

            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.PC.Spec);

            EmitMoveNextEpilogue(ec);

            ec.MarkLabel(move_next_error);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(0);
                ec.Emit(OpCodes.Ret);
            }

            ec.MarkLabel(move_next_ok);

            if (ReturnType.Kind != MemberKind.Void)
            {
                ec.EmitInt(1);
                ec.Emit(OpCodes.Ret);
            }

            SymbolWriter.EndIteratorDispatcher(ec);
        }
Ejemplo n.º 44
0
		public override void EmitStatement (EmitContext ec)
		{
			if (conditionalAccessReceiver) {
				ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ()) {
					Statement = true
				};
			}

			var call = new CallEmitter ();
			call.InstanceExpression = InstanceExpr;
			call.EmitStatement (ec, method, arguments, loc);

			if (conditionalAccessReceiver)
				ec.CloseConditionalAccess (null);
		}
Ejemplo n.º 45
0
		protected override void DoEmit (EmitContext ec)
		{
			if (empty) {
				expr.EmitSideEffect (ec);
				return;
			}

			Label old_begin = ec.LoopBegin;
			Label old_end = ec.LoopEnd;
			
			ec.LoopBegin = ec.DefineLabel ();
			ec.LoopEnd = ec.DefineLabel ();

			//
			// Inform whether we are infinite or not
			//
			if (expr is Constant){
				// expr is 'true', since the 'empty' case above handles the 'false' case
				ec.MarkLabel (ec.LoopBegin);
				expr.EmitSideEffect (ec);
				Statement.Emit (ec);
				ec.Emit (OpCodes.Br, ec.LoopBegin);
					
				//
				// Inform that we are infinite (ie, `we return'), only
				// if we do not `break' inside the code.
				//
				ec.MarkLabel (ec.LoopEnd);
			} else {
				Label while_loop = ec.DefineLabel ();

				ec.Emit (OpCodes.Br, ec.LoopBegin);
				ec.MarkLabel (while_loop);

				Statement.Emit (ec);
			
				ec.MarkLabel (ec.LoopBegin);
				ec.Mark (loc);

				expr.EmitBranchable (ec, while_loop, true);
				
				ec.MarkLabel (ec.LoopEnd);
			}	

			ec.LoopBegin = old_begin;
			ec.LoopEnd = old_end;
		}
Ejemplo n.º 46
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);
                }
            }
        }
Ejemplo n.º 47
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;
            }

            if (unwrap != null)
            {
                unwrap.Store(ec);
                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);
            }
            else
            {
                EmitLoad(ec);

                if (conditionalAccess)
                {
                    ec.Emit(OpCodes.Dup);
                    ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);
                    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 (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);
                }
            }
        }
Ejemplo n.º 48
0
        public void EmitDispose(EmitContext ec)
        {
            Label end = ec.DefineLabel ();

            Label [] labels = null;
            int n_resume_points = resume_points == null ? 0 : resume_points.Count;
            for (int i = 0; i < n_resume_points; ++i) {
                ResumableStatement s = (ResumableStatement) resume_points [i];
                Label ret = s.PrepareForDispose (ec, end);
                if (ret.Equals (end) && labels == null)
                    continue;
                if (labels == null) {
                    labels = new Label [resume_points.Count + 1];
                    for (int j = 0; j <= i; ++j)
                        labels [j] = end;
                }
                labels [i+1] = ret;
            }

            if (labels != null) {
                current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
                ec.Emit (OpCodes.Ldarg_0);
                ec.Emit (OpCodes.Ldfld, IteratorHost.PC.Spec);
                ec.Emit (OpCodes.Stloc, current_pc);
            }

            ec.Emit (OpCodes.Ldarg_0);
            ec.EmitInt ((int) State.After);
            ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec);

            if (labels != null) {
                //SymbolWriter.StartIteratorDispatcher (ec.ig);
                ec.Emit (OpCodes.Ldloc, current_pc);
                ec.Emit (OpCodes.Switch, labels);
                //SymbolWriter.EndIteratorDispatcher (ec.ig);

                foreach (ResumableStatement s in resume_points)
                    s.EmitForDispose (ec, this, end, true);
            }

            ec.MarkLabel (end);
        }
Ejemplo n.º 49
0
		public Label PrepareForEmit (EmitContext ec)
		{
			if (!prepared) {
				prepared = true;
				resume_point = ec.DefineLabel ();
			}
			return resume_point;
		}
Ejemplo n.º 50
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);
                }
Ejemplo n.º 51
0
		protected sealed override void DoEmit (EmitContext ec)
		{
			EmitPreTryBody (ec);

			if (resume_points != null) {
				ec.EmitInt ((int) Iterator.State.Running);
				ec.Emit (OpCodes.Stloc, iter.CurrentPC);
			}

			ec.BeginExceptionBlock ();

			if (resume_points != null) {
				ec.MarkLabel (resume_point);

				// For normal control flow, we want to fall-through the Switch
				// So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
				ec.Emit (OpCodes.Ldloc, iter.CurrentPC);
				ec.EmitInt (first_resume_pc);
				ec.Emit (OpCodes.Sub);

				Label [] labels = new Label [resume_points.Count];
				for (int i = 0; i < resume_points.Count; ++i)
					labels [i] = resume_points [i].PrepareForEmit (ec);
				ec.Emit (OpCodes.Switch, labels);
			}

			EmitTryBody (ec);

			ec.BeginFinallyBlock ();

			Label start_finally = ec.DefineLabel ();
			if (resume_points != null) {
				ec.Emit (OpCodes.Ldloc, iter.SkipFinally);
				ec.Emit (OpCodes.Brfalse_S, start_finally);
				ec.Emit (OpCodes.Endfinally);
			}

			ec.MarkLabel (start_finally);
			EmitFinallyBody (ec);

			ec.EndExceptionBlock ();
		}
Ejemplo n.º 52
0
		void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
		{
			Label l_initialized = ec.DefineLabel ();

			//
			// Skip initialization when value is null
			//
			value.EmitBranchable (ec, null_target, false);

			//
			// Check if string dictionary is initialized and initialize
			//
			switch_cache_field.EmitBranchable (ec, l_initialized, true);
			string_dictionary.EmitStatement (ec);
			ec.MarkLabel (l_initialized);

			LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);

			ResolveContext rc = new ResolveContext (ec.MemberContext);

			if (TypeManager.generic_ienumerable_type != null) {
				Arguments get_value_args = new Arguments (2);
				get_value_args.Add (new Argument (value));
				get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
				Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
				if (get_item == null)
					return;

				//
				// A value was not found, go to default case
				//
				get_item.EmitBranchable (ec, default_target, false);
			} else {
				Arguments get_value_args = new Arguments (1);
				get_value_args.Add (new Argument (value));

				Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
				if (get_item == null)
					return;

				LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
				get_item_object.EmitAssign (ec, get_item, true, false);
				ec.Emit (OpCodes.Brfalse, default_target);

				ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
					new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc);

				get_item_int.EmitStatement (ec);
				get_item_object.Release (ec);
			}

			TableSwitchEmit (ec, string_switch_variable);
			string_switch_variable.Release (ec);
		}
Ejemplo n.º 53
0
        protected void EmitCall(EmitContext ec, Expression binder, Arguments arguments, bool isStatement)
        {
            //
            // This method generates all internal infrastructure for a dynamic call. The
            // reason why it's quite complicated is the mixture of dynamic and anonymous
            // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous
            // methods can generate temporary storey as well (AnonStorey). Handling MVAR
            // type parameters rewrite is non-trivial in such case as there are various
            // combinations possible therefore the mutator is not straightforward. Secondly
            // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit
            // correct Site field type and its access from EmitContext.
            //

            int dyn_args_count = arguments == null ? 0 : arguments.Count;
            int default_args   = isStatement ? 1 : 2;
            var module         = ec.Module;

            bool has_ref_out_argument = false;
            var  targs = new TypeExpression[dyn_args_count + default_args];

            targs[0] = new TypeExpression(module.PredefinedTypes.CallSite.TypeSpec, loc);

            TypeExpression[]     targs_for_instance = null;
            TypeParameterMutator mutator;

            var site_container = ec.CreateDynamicSite();

            if (context_mvars != null)
            {
                TypeParameters tparam;
                TypeContainer  sc = site_container;
                do
                {
                    tparam = sc.CurrentTypeParameters;
                    sc     = sc.Parent;
                } while (tparam == null);

                mutator = new TypeParameterMutator(context_mvars, tparam);

                if (!ec.IsAnonymousStoreyMutateRequired)
                {
                    targs_for_instance    = new TypeExpression[targs.Length];
                    targs_for_instance[0] = targs[0];
                }
            }
            else
            {
                mutator = null;
            }

            for (int i = 0; i < dyn_args_count; ++i)
            {
                Argument a = arguments[i];
                if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
                {
                    has_ref_out_argument = true;
                }

                var t = a.Type;

                // Convert any internal type like dynamic or null to object
                if (t.Kind == MemberKind.InternalCompilerType)
                {
                    t = ec.BuiltinTypes.Object;
                }

                if (targs_for_instance != null)
                {
                    targs_for_instance[i + 1] = new TypeExpression(t, loc);
                }

                if (mutator != null)
                {
                    t = t.Mutate(mutator);
                }

                targs[i + 1] = new TypeExpression(t, loc);
            }

            TypeExpr del_type = null;
            TypeExpr del_type_instance_access = null;

            if (!has_ref_out_argument)
            {
                string d_name = isStatement ? "Action" : "Func";

                TypeSpec  te      = null;
                Namespace type_ns = module.GlobalRootNamespace.GetNamespace("System", true);
                if (type_ns != null)
                {
                    te = type_ns.LookupType(module, d_name, dyn_args_count + default_args, LookupMode.IgnoreAccessibility, loc);
                }

                if (te != null)
                {
                    if (!isStatement)
                    {
                        var t = type;
                        if (t.Kind == MemberKind.InternalCompilerType)
                        {
                            t = ec.BuiltinTypes.Object;
                        }

                        if (targs_for_instance != null)
                        {
                            targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression(t, loc);
                        }

                        if (mutator != null)
                        {
                            t = t.Mutate(mutator);
                        }

                        targs[targs.Length - 1] = new TypeExpression(t, loc);
                    }

                    del_type = new GenericTypeExpr(te, new TypeArguments(targs), loc);
                    if (targs_for_instance != null)
                    {
                        del_type_instance_access = new GenericTypeExpr(te, new TypeArguments(targs_for_instance), loc);
                    }
                    else
                    {
                        del_type_instance_access = del_type;
                    }
                }
            }

            //
            // Create custom delegate when no appropriate predefined delegate has been found
            //
            Delegate d;

            if (del_type == null)
            {
                TypeSpec    rt = isStatement ? ec.BuiltinTypes.Void : type;
                Parameter[] p  = new Parameter[dyn_args_count + 1];
                p[0] = new Parameter(targs[0], "p0", Parameter.Modifier.NONE, null, loc);

                var site  = ec.CreateDynamicSite();
                int index = site.Containers == null ? 0 : site.Containers.Count;

                if (mutator != null)
                {
                    rt = mutator.Mutate(rt);
                }

                for (int i = 1; i < dyn_args_count + 1; ++i)
                {
                    p[i] = new Parameter(targs[i], "p" + i.ToString("X"), arguments[i - 1].Modifier, null, loc);
                }

                d = new Delegate(site, new TypeExpression(rt, loc),
                                 Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
                                 new MemberName("Container" + index.ToString("X")),
                                 new ParametersCompiled(p), null);

                d.CreateContainer();
                d.DefineContainer();
                d.Define();
                d.PrepareEmit();

                site.AddTypeContainer(d);

                //
                // Add new container to inflated site container when the
                // member cache already exists
                //
                if (site.CurrentType is InflatedTypeSpec && index > 0)
                {
                    site.CurrentType.MemberCache.AddMember(d.CurrentType);
                }

                del_type = new TypeExpression(d.CurrentType, loc);
                if (targs_for_instance != null)
                {
                    del_type_instance_access = null;
                }
                else
                {
                    del_type_instance_access = del_type;
                }
            }
            else
            {
                d = null;
            }

            var site_type_decl = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments(del_type), loc);
            var field          = site_container.CreateCallSiteField(site_type_decl, loc);

            if (field == null)
            {
                return;
            }

            if (del_type_instance_access == null)
            {
                var dt = d.CurrentType.DeclaringType.MakeGenericType(module, context_mvars.Types);
                del_type_instance_access = new TypeExpression(MemberCache.GetMember(dt, d.CurrentType), loc);
            }

            var instanceAccessExprType = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec,
                                                             new TypeArguments(del_type_instance_access), loc);

            if (instanceAccessExprType.ResolveAsType(ec.MemberContext) == null)
            {
                return;
            }

            bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired;

            TypeSpec gt;

            if (inflate_using_mvar || context_mvars == null)
            {
                gt = site_container.CurrentType;
            }
            else
            {
                gt = site_container.CurrentType.MakeGenericType(module, context_mvars.Types);
            }

            // When site container already exists the inflated version has to be
            // updated manually to contain newly created field
            if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1)
            {
                var tparams  = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes;
                var inflator = new TypeParameterInflator(module, gt, tparams, gt.TypeArguments);
                gt.MemberCache.AddMember(field.InflateMember(inflator));
            }

            FieldExpr site_field_expr = new FieldExpr(MemberCache.GetMember(gt, field), loc);

            BlockContext bc = new BlockContext(ec.MemberContext, null, ec.BuiltinTypes.Void);

            Arguments args = new Arguments(1);

            args.Add(new Argument(binder));
            StatementExpression s = new StatementExpression(new SimpleAssign(site_field_expr, new Invocation(new MemberAccess(instanceAccessExprType, "Create"), args)));

            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                var conditionalAccessReceiver = IsConditionalAccessReceiver;
                var ca = ec.ConditionalAccess;

                if (conditionalAccessReceiver)
                {
                    ec.ConditionalAccess = new ConditionalAccessContext(type, ec.DefineLabel())
                    {
                        Statement = isStatement
                    };

                    //
                    // Emit conditional access expressions before dynamic call
                    // is initialized. It pushes site_field_expr on stack before
                    // the actual instance argument is emited which would cause
                    // jump from non-empty stack.
                    //
                    EmitConditionalAccess(ec);
                }

                if (s.Resolve(bc))
                {
                    Statement init = new If(new Binary(Binary.Operator.Equality, site_field_expr, new NullLiteral(loc)), s, loc);
                    init.Emit(ec);
                }

                args = new Arguments(1 + dyn_args_count);
                args.Add(new Argument(site_field_expr));
                if (arguments != null)
                {
                    int arg_pos = 1;
                    foreach (Argument a in arguments)
                    {
                        if (a is NamedArgument)
                        {
                            // Name is not valid in this context
                            args.Add(new Argument(a.Expr, a.ArgType));
                        }
                        else
                        {
                            args.Add(a);
                        }

                        if (inflate_using_mvar && a.Type != targs[arg_pos].Type)
                        {
                            a.Expr.Type = targs[arg_pos].Type;
                        }

                        ++arg_pos;
                    }
                }

                var target = new DelegateInvocation(new MemberAccess(site_field_expr, "Target", loc).Resolve(bc), args, false, loc).Resolve(bc);
                if (target != null)
                {
                    target.Emit(ec);
                }

                if (conditionalAccessReceiver)
                {
                    ec.CloseConditionalAccess(!isStatement && type.IsNullableType ? type : null);
                    ec.ConditionalAccess = ca;
                }
            }
        }
Ejemplo n.º 54
0
		public override void Emit (EmitContext ec)
		{
			//
			// Use same anonymous method implementation for scenarios where same
			// code is used from multiple blocks, e.g. field initializers
			//
			if (method == null) {
				//
				// Delay an anonymous method definition to avoid emitting unused code
				// for unreachable blocks or expression trees
				//
				method = DoCreateMethodHost (ec);
				method.Define ();
			}

			bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
			if (is_static && am_cache == null) {
				//
				// Creates a field cache to store delegate instance if it's not generic
				//
				if (!method.MemberName.IsGeneric) {
					var parent = method.Parent.PartialContainer;
					int id = parent.AnonymousMethodsCounter++;
					var cache_type = storey != null && storey.Mutator != null ? storey.Mutator.Mutate (type) : type;

					am_cache = new Field (parent, new TypeExpression (cache_type, loc),
						Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
						new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "am$cache", id), loc), null);
					am_cache.Define ();
					parent.AddField (am_cache);
				} else {
					// TODO: Implement caching of generated generic static methods
					//
					// Idea:
					//
					// Some extra class is needed to capture variable generic type
					// arguments. Maybe we could re-use anonymous types, with a unique
					// anonymous method id, but they are quite heavy.
					//
					// Consider : "() => typeof(T);"
					//
					// We need something like
					// static class Wrap<Tn, Tm, DelegateType> {
					//		public static DelegateType cache;
					// }
					//
					// We then specialize local variable to capture all generic parameters
					// and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
					//
				}
			}

			Label l_initialized = ec.DefineLabel ();

			if (am_cache != null) {
				ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
				ec.Emit (OpCodes.Brtrue_S, l_initialized);
			}

			//
			// Load method delegate implementation
			//

			if (is_static) {
				ec.EmitNull ();
			} else if (storey != null) {
				Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext));
				if (e != null) {
					e.Emit (ec);
				}
			} else {
				ec.EmitThis ();

				//
				// Special case for value type storey where this is not lifted but
				// droped off to parent class
				//
				for (var b = Block.Parent; b != null; b = b.Parent) {
					if (b.ParametersBlock.StateMachine != null) {
						ec.Emit (OpCodes.Ldfld, b.ParametersBlock.StateMachine.HoistedThis.Field.Spec);
						break;
					}
				}
			}

			var delegate_method = method.Spec;
			if (storey != null && storey.MemberName.IsGeneric) {
				TypeSpec t = storey.Instance.Type;

				//
				// Mutate anonymous method instance type if we are in nested
				// hoisted generic anonymous method storey
				//
				if (ec.IsAnonymousStoreyMutateRequired) {
					t = storey.Mutator.Mutate (t);
				}

				ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
			} else {
				if (delegate_method.IsGeneric)
					delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);

				ec.Emit (OpCodes.Ldftn, delegate_method);
			}

			var constructor_method = Delegate.GetConstructor (type);
			ec.Emit (OpCodes.Newobj, constructor_method);

			if (am_cache != null) {
				ec.Emit (OpCodes.Stsfld, am_cache.Spec);
				ec.MarkLabel (l_initialized);
				ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
			}
		}
Ejemplo n.º 55
0
		protected override void DoEmit (EmitContext ec)
		{
			//
			// Needed to emit anonymous storey initialization
			// Otherwise it does not contain any statements for now
			//
			block.Emit (ec);

			default_target = ec.DefineLabel ();
			null_target = ec.DefineLabel ();

			// Store variable for comparission purposes
			// TODO: Don't duplicate non-captured VariableReference
			LocalTemporary value;
			if (HaveUnwrap) {
				value = new LocalTemporary (SwitchType);
				unwrap.EmitCheck (ec);
				ec.Emit (OpCodes.Brfalse, null_target);
				new_expr.Emit (ec);
				value.Store (ec);
			} else if (!is_constant) {
				value = new LocalTemporary (SwitchType);
				new_expr.Emit (ec);
				value.Store (ec);
			} else
				value = null;

			//
			// Setup the codegen context
			//
			Label old_end = ec.LoopEnd;
			Switch old_switch = ec.Switch;
			
			ec.LoopEnd = ec.DefineLabel ();
			ec.Switch = this;

			// Emit Code.
			if (is_constant) {
				if (constant_section != null)
					constant_section.Block.Emit (ec);
			} else if (string_dictionary != null) {
				DoEmitStringSwitch (value, ec);
			} else {
				TableSwitchEmit (ec, value);
			}

			if (value != null)
				value.Release (ec);

			// Restore context state. 
			ec.MarkLabel (ec.LoopEnd);

			//
			// Restore the previous context
			//
			ec.LoopEnd = old_end;
			ec.Switch = old_switch;
		}