コード例 #1
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);
            }
        }
コード例 #2
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);
            }
        }
コード例 #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
        /// <summary>
        ///   C# allows this kind of scenarios:
        ///   interface I { void M (); }
        ///   class X { public void M (); }
        ///   class Y : X, I { }
        ///
        ///   For that case, we create an explicit implementation function
        ///   I.M in Y.
        /// </summary>
        void DefineProxy(TypeSpec iface, MethodSpec base_method, MethodSpec iface_method)
        {
            // TODO: Handle nested iface names
            string proxy_name;
            var    ns = iface.MemberDefinition.Namespace;

            if (string.IsNullOrEmpty(ns))
            {
                proxy_name = iface.MemberDefinition.Name + "." + iface_method.Name;
            }
            else
            {
                proxy_name = ns + "." + iface.MemberDefinition.Name + "." + iface_method.Name;
            }

            var param = iface_method.Parameters;

            MethodBuilder proxy = container.TypeBuilder.DefineMethod(
                proxy_name,
                MethodAttributes.Private |
                MethodAttributes.HideBySig |
                MethodAttributes.NewSlot |
                MethodAttributes.CheckAccessOnOverride |
                MethodAttributes.Virtual | MethodAttributes.Final,
                CallingConventions.Standard | CallingConventions.HasThis,
                base_method.ReturnType.GetMetaInfo(), param.GetMetaInfo());

            if (iface_method.IsGeneric)
            {
                var gnames = iface_method.GenericDefinition.TypeParameters.Select(l => l.Name).ToArray();
                proxy.DefineGenericParameters(gnames);
            }

            for (int i = 0; i < param.Count; i++)
            {
                string name = param.FixedParameters [i].Name;
                ParameterAttributes attr = ParametersCompiled.GetParameterAttribute(param.FixedParameters [i].ModFlags);
                proxy.DefineParameter(i + 1, attr, name);
            }

            int top = param.Count;
            var ec  = new EmitContext(new ProxyMethodContext(container), proxy.GetILGenerator(), null, null);

            ec.EmitThis();
            // TODO: GetAllParametersArguments
            for (int i = 0; i < top; i++)
            {
                ec.EmitArgumentLoad(i);
            }

            ec.Emit(OpCodes.Call, base_method);
            ec.Emit(OpCodes.Ret);

            container.TypeBuilder.DefineMethodOverride(proxy, (MethodInfo)iface_method.GetMetaInfo());
        }
コード例 #5
0
		/// <summary>
		///   C# allows this kind of scenarios:
		///   interface I { void M (); }
		///   class X { public void M (); }
		///   class Y : X, I { }
		///
		///   For that case, we create an explicit implementation function
		///   I.M in Y.
		/// </summary>
		void DefineProxy (TypeSpec iface, MethodSpec base_method, MethodSpec iface_method)
		{
			// TODO: Handle nested iface names
			string proxy_name;
			var ns = iface.MemberDefinition.Namespace;
			if (string.IsNullOrEmpty (ns))
				proxy_name = iface.MemberDefinition.Name + "." + iface_method.Name;
			else
				proxy_name = ns + "." + iface.MemberDefinition.Name + "." + iface_method.Name;

			var param = iface_method.Parameters;

			MethodBuilder proxy = container.TypeBuilder.DefineMethod (
				proxy_name,
				MethodAttributes.Private |
				MethodAttributes.HideBySig |
				MethodAttributes.NewSlot |
				MethodAttributes.CheckAccessOnOverride |
				MethodAttributes.Virtual | MethodAttributes.Final,
				CallingConventions.Standard | CallingConventions.HasThis,
				base_method.ReturnType.GetMetaInfo (), param.GetMetaInfo ());

			if (iface_method.IsGeneric) {
				var gnames = iface_method.GenericDefinition.TypeParameters.Select (l => l.Name).ToArray ();
				proxy.DefineGenericParameters (gnames);
			}

			for (int i = 0; i < param.Count; i++) {
				string name = param.FixedParameters [i].Name;
				ParameterAttributes attr = ParametersCompiled.GetParameterAttribute (param.FixedParameters [i].ModFlags);
				proxy.DefineParameter (i + 1, attr, name);
			}

			int top = param.Count;
			var ec = new EmitContext (new ProxyMethodContext (container), proxy.GetILGenerator (), null, null);
			ec.EmitThis ();
			// TODO: GetAllParametersArguments
			for (int i = 0; i < top; i++)
				ec.EmitArgumentLoad (i);

			ec.Emit (OpCodes.Call, base_method);
			ec.Emit (OpCodes.Ret);

			container.TypeBuilder.DefineMethodOverride (proxy, (MethodInfo) iface_method.GetMetaInfo ());
		}
コード例 #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 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);
			}
		}