コード例 #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);
            }
        }
コード例 #2
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);

            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);
            }
        }
コード例 #3
0
                protected override void DoEmit(EmitContext ec)
                {
                    Label label_init = ec.DefineLabel();

                    ec.EmitThis();
                    ec.Emit(OpCodes.Ldflda, host.PC.Spec);
                    ec.EmitInt((int)State.Start);
                    ec.EmitInt((int)State.Uninitialized);

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

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

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

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

                    ec.MarkLabel(label_init);

                    new_storey.Emit(ec);
                    ec.Emit(OpCodes.Ret);
                }
コード例 #4
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);
        }
コード例 #5
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);
            }
        }
コード例 #6
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]);

            iterator_body_end = ec.DefineLabel();

            block.EmitEmbedded(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.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);
            }
        }
コード例 #7
0
        public void EmitDispose(EmitContext ec)
        {
            if (resume_points == null)
            {
                return;
            }

            Label end = ec.DefineLabel();

            Label[] labels = null;
            for (int i = 0; i < resume_points.Count; ++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.EmitThis();
                ec.Emit(OpCodes.Ldfld, storey.PC.Spec);
                ec.Emit(OpCodes.Stloc, current_pc);
            }

            ec.EmitThis();
            ec.EmitInt(1);
            ec.Emit(OpCodes.Stfld, ((IteratorStorey)storey).DisposingField.Spec);

            ec.EmitThis();
            ec.EmitInt((int)IteratorStorey.State.After);
            ec.Emit(OpCodes.Stfld, storey.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, current_pc, end, true);
                }
            }

            ec.MarkLabel(end);
        }
コード例 #8
0
        public void EmitPrologue(EmitContext ec)
        {
            awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(expr.Type, loc);

            var fe_awaiter = new FieldExpr(awaiter, loc);

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

            //
            // awaiter = expr.GetAwaiter ();
            //
            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                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);

                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);
        }
コード例 #9
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);
			}
		}