Ejemplo n.º 1
0
        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)
            {
                TypeParameter[] 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";

                TypeExpr  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, Location.Null);
                }

                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.Type, new TypeArguments(targs), loc);
                    if (targs_for_instance != null)
                    {
                        del_type_instance_access = new GenericTypeExpr(te.Type, 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.Types == null ? 0 : site.Types.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.NamespaceEntry, site, new TypeExpression(rt, loc),
                                 Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
                                 new MemberName("Container" + index.ToString("X")),
                                 new ParametersCompiled(p), null);

                d.CreateType();
                d.DefineType();
                d.Define();
                d.Emit();

                site.AddDelegate(d);
                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.Select(l => l.Type).ToArray());
                del_type_instance_access = new TypeExpression(MemberCache.GetMember(dt, d.CurrentType), loc);
            }

            FullNamedExpression instanceAccessExprType = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec,
                                                                             new TypeArguments(del_type_instance_access), loc);

            BlockContext bc = new BlockContext(ec.MemberContext, null, ec.BuiltinTypes.Void);

            instanceAccessExprType = instanceAccessExprType.ResolveAsType(bc);
            if (instanceAccessExprType == 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.Select(l => l.Type).ToArray());
            }

            // When site container already exists the inflated version has to be
            // updated manually to contain newly created field
            if (gt is InflatedTypeSpec && site_container.Fields.Count > 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);

            SymbolWriter.OpenCompilerGeneratedBlock(ec);

            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)));

            if (s.Resolve(bc))
            {
                Statement init = new If(new Binary(Binary.Operator.Equality, site_field_expr, new NullLiteral(loc), 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;
                }
            }

            Expression target = new DelegateInvocation(new MemberAccess(site_field_expr, "Target", loc).Resolve(bc), args, loc).Resolve(bc);

            if (target != null)
            {
                target.Emit(ec);
            }

            SymbolWriter.CloseCompilerGeneratedBlock(ec);
        }
Ejemplo n.º 2
0
        TypeExpr CreateSiteType(EmitContext ec, Arguments arguments, int dyn_args_count, bool is_statement)
        {
            int default_args = is_statement ? 1 : 2;
            var module       = ec.MemberContext.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);
            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 = TypeManager.object_type;
                }

                targs [i + 1] = new TypeExpression(t, loc);
            }

            TypeExpr del_type = null;

            if (!has_ref_out_argument)
            {
                string d_name = is_statement ? "Action" : "Func";

                TypeExpr  te      = null;
                Namespace type_ns = module.GlobalRootNamespace.GetNamespace("System", true);
                if (type_ns != null)
                {
                    te = type_ns.LookupType(module.Compiler, d_name, dyn_args_count + default_args, true, Location.Null);
                }

                if (te != null)
                {
                    if (!is_statement)
                    {
                        targs [targs.Length - 1] = new TypeExpression(type, loc);
                    }

                    del_type = new GenericTypeExpr(te.Type, new TypeArguments(targs), loc);
                }
            }

            //
            // Create custom delegate when no appropriate predefined one is found
            //
            if (del_type == null)
            {
                TypeSpec    rt = is_statement ? TypeManager.void_type : 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.Types == null ? 0 : site.Types.Count;

                if (site.Mutator != null)
                {
                    rt = site.Mutator.Mutate(rt);
                }

                for (int i = 1; i < dyn_args_count + 1; ++i)
                {
                    var t = targs[i];
                    if (site.Mutator != null)
                    {
                        t.Type = site.Mutator.Mutate(t.Type);
                    }

                    p[i] = new Parameter(t, "p" + i.ToString("X"), arguments[i - 1].Modifier, null, loc);
                }

                Delegate d = new Delegate(site.NamespaceEntry, site, new TypeExpression(rt, loc),
                                          Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
                                          new MemberName("Container" + index.ToString("X")),
                                          new ParametersCompiled(p), null);

                d.CreateType();
                d.DefineType();
                d.Define();
                d.Emit();

                var inflated = site.AddDelegate(d);
                del_type = new TypeExpression(inflated, loc);
            }

            TypeExpr site_type = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments(del_type), loc);

            return(site_type);
        }