public override Expression DoResolve(ResolveContext ec) { method = new AnonymousMethodMethod(Storey, this, Storey, null, TypeManager.system_boolean_expr, Modifiers.PUBLIC, OriginalMethod.GetSignatureForError(), new MemberName("MoveNext", Location), ParametersCompiled.EmptyReadOnlyParameters); if (!Compatible(ec)) { return(null); } IteratorHost.DefineIteratorMembers(); eclass = ExprClass.Value; return(this); }
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); } }
protected override Expression DoResolve(ResolveContext ec) { method = new AnonymousMethodMethod (Storey, this, Storey, null, TypeManager.system_boolean_expr, Modifiers.PUBLIC, OriginalMethod.GetSignatureForError (), new MemberName ("MoveNext", Location), ParametersCompiled.EmptyReadOnlyParameters); if (Compatible (ec) == null) return null; eclass = ExprClass.Value; return this; }
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) { TypeContainer parent = method.Parent.PartialContainer; int id = parent.Fields == null ? 0 : parent.Fields.Count; am_cache = new Field (parent, new TypeExpression (type, loc), Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedClass.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;" // } } ILGenerator ig = ec.ig; Label l_initialized = ig.DefineLabel (); if (am_cache != null) { ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder); ig.Emit (OpCodes.Brtrue_S, l_initialized); } // // Load method delegate implementation // if (is_static) { ig.Emit (OpCodes.Ldnull); } else if (storey != null) { Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext)); if (e != null) e.Emit (ec); } else { ig.Emit (OpCodes.Ldarg_0); } MethodInfo delegate_method = method.MethodBuilder; if (storey != null && storey.MemberName.IsGeneric) { Type t = storey.Instance.Type; // // Mutate anonymous method instance type if we are in nested // hoisted generic anonymous method storey // if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null && ec.CurrentAnonymousMethod.Storey.IsGeneric) { t = storey.GetGenericStorey ().MutateType (t); } #if GMCS_SOURCE delegate_method = TypeBuilder.GetMethod (t, delegate_method); #else throw new NotSupportedException (); #endif } ig.Emit (OpCodes.Ldftn, delegate_method); ConstructorInfo constructor_method = Delegate.GetConstructor (RootContext.ToplevelTypes.Compiler, ec.CurrentType, type); #if MS_COMPATIBLE if (type.IsGenericType && type is TypeBuilder) constructor_method = TypeBuilder.GetConstructor (type, constructor_method); #endif ig.Emit (OpCodes.Newobj, constructor_method); if (am_cache != null) { ig.Emit (OpCodes.Stsfld, am_cache.FieldBuilder); ig.MarkLabel (l_initialized); ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder); } }
public override Expression DoResolve (EmitContext ec) { method = new AnonymousMethodMethod (Storey, this, Storey, null, TypeManager.system_boolean_expr, Modifiers.PUBLIC, OriginalMethod.GetSignatureForError (), new MemberName ("MoveNext", Location), Parameters.EmptyReadOnlyParameters); if (!Compatible (ec)) return null; IteratorHost.DefineIteratorMembers (); eclass = ExprClass.Value; type = ec.ReturnType; return this; }