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); } }
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); } } }
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); }
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); } }
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); } } }
public override void Emit (EmitContext ec) { ec.EmitNull (); // Only to make verifier happy if (type.IsGenericParameter) ec.Emit (OpCodes.Unbox_Any, type); }
public override void Emit (EmitContext ec) { if (Value == null) { ec.EmitNull (); return; } // // Use string.Empty for both literals and constants even if // it's not allowed at language level // if (Value.Length == 0 && ec.Module.Compiler.Settings.Optimize) { var string_type = ec.BuiltinTypes.String; if (ec.CurrentType != string_type) { var m = ec.Module.PredefinedMembers.StringEmpty.Get (); if (m != null) { ec.Emit (OpCodes.Ldsfld, m); return; } } } ec.Emit (OpCodes.Ldstr, Value); }