Esempio 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);
            }
        }
Esempio n. 2
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);
        }
Esempio n. 3
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);
		}
Esempio n. 4
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);
		}
Esempio n. 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);
			}
		}
Esempio n. 6
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);
		}
Esempio n. 7
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 ();
				method.PrepareEmit ();
			}

			bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
			if (is_static && am_cache == null && !ec.IsStaticConstructor) {
				//
				// 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
				//
				if (ec.CurrentAnonymousMethod != null && ec.AsyncTaskStorey != null)
					ec.Emit (OpCodes.Ldfld, ec.AsyncTaskStorey.HoistedThis.Field.Spec);
			}

			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) {
					TypeParameterSpec[] tparams;
					var sm = ec.CurrentAnonymousMethod == null ? null : ec.CurrentAnonymousMethod.Storey as StateMachine;
					if (sm != null && sm.OriginalTypeParameters != null) {
						tparams = sm.CurrentTypeParameters.Types;
					} else {
						tparams = method.TypeParameters;
					}

					delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, tparams);
				}

				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);
			}
		}
Esempio n. 8
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);
				}
			}
		}