// // Creates a proxy base method call inside this container for hoisted base member calls // public MethodSpec CreateHoistedBaseCallProxy (ResolveContext rc, MethodSpec method) { Method proxy_method; // // One proxy per base method is enough // if (hoisted_base_call_proxies == null) { hoisted_base_call_proxies = new Dictionary<MethodSpec, Method> (); proxy_method = null; } else { hoisted_base_call_proxies.TryGetValue (method, out proxy_method); } if (proxy_method == null) { string name = CompilerGeneratedContainer.MakeName (method.Name, null, "BaseCallProxy", hoisted_base_call_proxies.Count); MemberName member_name; TypeArguments targs = null; TypeSpec return_type = method.ReturnType; var local_param_types = method.Parameters.Types; if (method.IsGeneric) { // // Copy all base generic method type parameters info // var hoisted_tparams = method.GenericDefinition.TypeParameters; var tparams = new TypeParameters (); targs = new TypeArguments (); targs.Arguments = new TypeSpec[hoisted_tparams.Length]; for (int i = 0; i < hoisted_tparams.Length; ++i) { var tp = hoisted_tparams[i]; var local_tp = new TypeParameter (tp, null, new MemberName (tp.Name, Location), null); tparams.Add (local_tp); targs.Add (new SimpleName (tp.Name, Location)); targs.Arguments[i] = local_tp.Type; } member_name = new MemberName (name, tparams, Location); // // Mutate any method type parameters from original // to newly created hoisted version // var mutator = new TypeParameterMutator (hoisted_tparams, tparams); return_type = mutator.Mutate (return_type); local_param_types = mutator.Mutate (local_param_types); } else { member_name = new MemberName (name); } var base_parameters = new Parameter[method.Parameters.Count]; for (int i = 0; i < base_parameters.Length; ++i) { var base_param = method.Parameters.FixedParameters[i]; base_parameters[i] = new Parameter (new TypeExpression (local_param_types [i], Location), base_param.Name, base_param.ModFlags, null, Location); base_parameters[i].Resolve (this, i); } var cloned_params = ParametersCompiled.CreateFullyResolved (base_parameters, method.Parameters.Types); if (method.Parameters.HasArglist) { cloned_params.FixedParameters[0] = new Parameter (null, "__arglist", Parameter.Modifier.NONE, null, Location); cloned_params.Types[0] = Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (); } // Compiler generated proxy proxy_method = new Method (this, new TypeExpression (return_type, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN, member_name, cloned_params, null); var block = new ToplevelBlock (Compiler, proxy_method.ParameterInfo, Location) { IsCompilerGenerated = true }; var mg = MethodGroupExpr.CreatePredefined (method, method.DeclaringType, Location); mg.InstanceExpression = new BaseThis (method.DeclaringType, Location); if (targs != null) mg.SetTypeArguments (rc, targs); // Get all the method parameters and pass them as arguments var real_base_call = new Invocation (mg, block.GetAllParametersArguments ()); Statement statement; if (method.ReturnType.Kind == MemberKind.Void) statement = new StatementExpression (real_base_call); else statement = new Return (real_base_call, Location); block.AddStatement (statement); proxy_method.Block = block; members.Add (proxy_method); proxy_method.Define (); proxy_method.PrepareEmit (); hoisted_base_call_proxies.Add (method, proxy_method); } return proxy_method.Spec; }
public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mods, MemberKind kind) : base (parent, name, mods | Modifiers.PRIVATE, kind) { if (tparams != null) { var type_params = name.TypeParameters; var src = new TypeParameterSpec[tparams.Count]; var dst = new TypeParameterSpec[tparams.Count]; for (int i = 0; i < tparams.Count; ++i) { type_params[i] = tparams[i].CreateHoistedCopy (spec); src[i] = tparams[i].Type; dst[i] = type_params[i].Type; } // A copy is not enough, inflate any type parameter constraints // using a new type parameters var inflator = new TypeParameterInflator (this, null, src, dst); for (int i = 0; i < tparams.Count; ++i) { src[i].InflateConstraints (inflator, dst[i]); } mutator = new TypeParameterMutator (tparams, type_params); } }
public MethodSpec Mutate (TypeParameterMutator mutator) { var targs = TypeArguments; if (targs != null) targs = mutator.Mutate (targs); var decl = DeclaringType; if (DeclaringType.IsGenericOrParentIsGeneric) { decl = mutator.Mutate (decl); } if (targs == TypeArguments && decl == DeclaringType) return this; var ms = (MethodSpec) MemberwiseClone (); if (decl != DeclaringType) { ms.inflatedMetaInfo = null; ms.declaringType = decl; ms.state |= StateFlags.PendingMetaInflate; } if (targs != null) { ms.targs = targs; ms.state |= StateFlags.PendingMakeMethod; } return ms; }
public FieldSpec Mutate (TypeParameterMutator mutator) { var decl = DeclaringType; if (DeclaringType.IsGenericOrParentIsGeneric) decl = mutator.Mutate (decl); if (decl == DeclaringType) return this; var fs = (FieldSpec) MemberwiseClone (); fs.declaringType = decl; fs.state |= StateFlags.PendingMetaInflate; // Gets back FieldInfo in case of metaInfo was inflated fs.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo; return fs; }
public MethodSpec Mutate (TypeParameterMutator mutator) { var targs = TypeArguments; if (targs != null) targs = mutator.Mutate (targs); var decl = DeclaringType; if (DeclaringType.IsGenericOrParentIsGeneric) { decl = mutator.Mutate (decl); } if (targs == TypeArguments && decl == DeclaringType) return this; var ms = (MethodSpec) MemberwiseClone (); if (decl != DeclaringType) { // Gets back MethodInfo in case of metaInfo was inflated ms.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo; ms.declaringType = decl; ms.state |= StateFlags.PendingMetaInflate; } if (targs != null) { ms.targs = targs; ms.state |= StateFlags.PendingMakeMethod; } return ms; }
protected void EmitCall (EmitContext ec, Expression binder, Arguments arguments, bool isStatement) { // // This method generates all internal infrastructure for a dynamic call. The // reason why it's quite complicated is the mixture of dynamic and anonymous // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous // methods can generate temporary storey as well (AnonStorey). Handling MVAR // type parameters rewrite is non-trivial in such case as there are various // combinations possible therefore the mutator is not straightforward. Secondly // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit // correct Site field type and its access from EmitContext. // int dyn_args_count = arguments == null ? 0 : arguments.Count; int default_args = isStatement ? 1 : 2; var module = ec.Module; bool has_ref_out_argument = false; var targs = new TypeExpression[dyn_args_count + default_args]; targs[0] = new TypeExpression (module.PredefinedTypes.CallSite.TypeSpec, loc); TypeExpression[] targs_for_instance = null; TypeParameterMutator mutator; var site_container = ec.CreateDynamicSite (); if (context_mvars != null) { TypeParameters tparam; TypeContainer sc = site_container; do { tparam = sc.CurrentTypeParameters; sc = sc.Parent; } while (tparam == null); mutator = new TypeParameterMutator (context_mvars, tparam); if (!ec.IsAnonymousStoreyMutateRequired) { targs_for_instance = new TypeExpression[targs.Length]; targs_for_instance[0] = targs[0]; } } else { mutator = null; } for (int i = 0; i < dyn_args_count; ++i) { Argument a = arguments[i]; if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref) has_ref_out_argument = true; var t = a.Type; // Convert any internal type like dynamic or null to object if (t.Kind == MemberKind.InternalCompilerType) t = ec.BuiltinTypes.Object; if (targs_for_instance != null) targs_for_instance[i + 1] = new TypeExpression (t, loc); if (mutator != null) t = t.Mutate (mutator); targs[i + 1] = new TypeExpression (t, loc); } TypeExpr del_type = null; TypeExpr del_type_instance_access = null; if (!has_ref_out_argument) { string d_name = isStatement ? "Action" : "Func"; TypeSpec te = null; Namespace type_ns = module.GlobalRootNamespace.GetNamespace ("System", true); if (type_ns != null) { te = type_ns.LookupType (module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc); } if (te != null) { if (!isStatement) { var t = type; if (t.Kind == MemberKind.InternalCompilerType) t = ec.BuiltinTypes.Object; if (targs_for_instance != null) targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression (t, loc); if (mutator != null) t = t.Mutate (mutator); targs[targs.Length - 1] = new TypeExpression (t, loc); } del_type = new GenericTypeExpr (te, new TypeArguments (targs), loc); if (targs_for_instance != null) del_type_instance_access = new GenericTypeExpr (te, new TypeArguments (targs_for_instance), loc); else del_type_instance_access = del_type; } } // // Create custom delegate when no appropriate predefined delegate has been found // Delegate d; if (del_type == null) { TypeSpec rt = isStatement ? ec.BuiltinTypes.Void : type; Parameter[] p = new Parameter[dyn_args_count + 1]; p[0] = new Parameter (targs[0], "p0", Parameter.Modifier.NONE, null, loc); var site = ec.CreateDynamicSite (); int index = site.Containers == null ? 0 : site.Containers.Count; if (mutator != null) rt = mutator.Mutate (rt); for (int i = 1; i < dyn_args_count + 1; ++i) { p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc); } d = new Delegate (site, new TypeExpression (rt, loc), Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED, new MemberName ("Container" + index.ToString ("X")), new ParametersCompiled (p), null); d.CreateContainer (); d.DefineContainer (); d.Define (); d.PrepareEmit (); site.AddTypeContainer (d); // // Add new container to inflated site container when the // member cache already exists // if (site.CurrentType is InflatedTypeSpec && index > 0) site.CurrentType.MemberCache.AddMember (d.CurrentType); del_type = new TypeExpression (d.CurrentType, loc); if (targs_for_instance != null) { del_type_instance_access = null; } else { del_type_instance_access = del_type; } } else { d = null; } var site_type_decl = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type), loc); var field = site_container.CreateCallSiteField (site_type_decl, loc); if (field == null) return; if (del_type_instance_access == null) { var dt = d.CurrentType.DeclaringType.MakeGenericType (module, context_mvars.Types); del_type_instance_access = new TypeExpression (MemberCache.GetMember (dt, d.CurrentType), loc); } var instanceAccessExprType = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type_instance_access), loc); if (instanceAccessExprType.ResolveAsType (ec.MemberContext) == null) return; bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired; TypeSpec gt; if (inflate_using_mvar || context_mvars == null) { gt = site_container.CurrentType; } else { gt = site_container.CurrentType.MakeGenericType (module, context_mvars.Types); } // When site container already exists the inflated version has to be // updated manually to contain newly created field if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) { var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes; var inflator = new TypeParameterInflator (module, gt, tparams, gt.TypeArguments); gt.MemberCache.AddMember (field.InflateMember (inflator)); } FieldExpr site_field_expr = new FieldExpr (MemberCache.GetMember (gt, field), loc); BlockContext bc = new BlockContext (ec.MemberContext, null, ec.BuiltinTypes.Void); Arguments args = new Arguments (1); args.Add (new Argument (binder)); StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (instanceAccessExprType, "Create"), args))); using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) { var conditionalAccessReceiver = IsConditionalAccessReceiver; var ca = ec.ConditionalAccess; if (conditionalAccessReceiver) { ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ()) { Statement = isStatement }; // // Emit conditional access expressions before dynamic call // is initialized. It pushes site_field_expr on stack before // the actual instance argument is emited which would cause // jump from non-empty stack. // EmitConditionalAccess (ec); } if (s.Resolve (bc)) { Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc); init.Emit (ec); } args = new Arguments (1 + dyn_args_count); args.Add (new Argument (site_field_expr)); if (arguments != null) { int arg_pos = 1; foreach (Argument a in arguments) { if (a is NamedArgument) { // Name is not valid in this context args.Add (new Argument (a.Expr, a.ArgType)); } else { args.Add (a); } if (inflate_using_mvar && a.Type != targs[arg_pos].Type) a.Expr.Type = targs[arg_pos].Type; ++arg_pos; } } var target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (bc), args, false, loc).Resolve (bc); if (target != null) { target.Emit (ec); } if (conditionalAccessReceiver) { ec.CloseConditionalAccess (!isStatement && type.IsNullableType ? type : null); ec.ConditionalAccess = ca; } } }
public HoistedStoreyClass (TypeContainer parent, MemberName name, TypeParameter[] tparams, Modifiers mod) : base (parent, name, mod | Modifiers.PRIVATE) { if (tparams != null) { type_params = new TypeParameter[tparams.Length]; var src = new TypeParameterSpec[tparams.Length]; var dst = new TypeParameterSpec[tparams.Length]; for (int i = 0; i < type_params.Length; ++i) { type_params[i] = tparams[i].CreateHoistedCopy (this, spec); src[i] = tparams[i].Type; dst[i] = type_params[i].Type; } // A copy is not enough, inflate any type parameter constraints // using a new type parameters var inflator = new TypeParameterInflator (this, null, src, dst); for (int i = 0; i < type_params.Length; ++i) { src[i].InflateConstraints (inflator, dst[i]); } mutator = new TypeParameterMutator (tparams, type_params); } }
public DynamicSiteClass(TypeContainer parent, MemberBase host, TypeParameter[] tparams) : base(parent, MakeMemberName (host, "DynamicSite", parent.DynamicSitesCounter, tparams, Location.Null), tparams, Modifiers.STATIC) { if (tparams != null) { mutator = new TypeParameterMutator (tparams, CurrentTypeParameters); } parent.DynamicSitesCounter++; }
public override TypeSpec Mutate (TypeParameterMutator mutator) { var targs = TypeArguments; if (targs != null) targs = mutator.Mutate (targs); var decl = DeclaringType; if (IsNested && DeclaringType.IsGenericOrParentIsGeneric) decl = mutator.Mutate (decl); if (targs == TypeArguments && decl == DeclaringType) return this; var mutated = (InflatedTypeSpec) MemberwiseClone (); if (decl != DeclaringType) { // Gets back MethodInfo in case of metaInfo was inflated //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info; mutated.declaringType = decl; mutated.state |= StateFlags.PendingMetaInflate; } if (targs != null) { mutated.targs = targs; mutated.info = null; } return mutated; }
Type CreateMetaInfo (TypeParameterMutator mutator) { // // Converts nested type arguments into right order // Foo<string, bool>.Bar<int> => string, bool, int // var all = new List<Type> (); TypeSpec type = this; TypeSpec definition = type; do { if (type.GetDefinition().IsGeneric) { all.InsertRange (0, type.TypeArguments != TypeSpec.EmptyTypes ? type.TypeArguments.Select (l => l.GetMetaInfo ()) : type.MemberDefinition.TypeParameters.Select (l => l.GetMetaInfo ())); } definition = definition.GetDefinition (); type = type.DeclaringType; } while (type != null); return definition.GetMetaInfo ().MakeGenericType (all.ToArray ()); }
public override TypeSpec Mutate (TypeParameterMutator mutator) { return mutator.Mutate (this); }