private Expression GenerateComplexCall(ObjExpr objx, GenContext context)
        {
            Expression call;

            Expression target = GenTargetExpression(objx, context);

            List <Expression>          exprs       = new List <Expression>(_args.Count);
            List <ParameterExpression> sbParams    = new List <ParameterExpression>();
            List <Expression>          sbInits     = new List <Expression>();
            List <Expression>          sbTransfers = new List <Expression>();

            GenerateComplexArgList(objx, context, _args, out exprs, out sbParams, out sbInits, out sbTransfers);

            Expression[] argExprs = ClrExtensions.ArrayInsert <Expression>(target, exprs);

            Type returnType = HasClrType ? ClrType : typeof(object);

            // TODO: Get rid of Default
            InvokeMemberBinder binder = new ClojureInvokeMemberBinder(ClojureContext.Default, _methodName, argExprs.Length, IsStaticCall);
            //DynamicExpression dyn = Expression.Dynamic(binder, returnType, argExprs);
            DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), argExprs);

            //if (context.Mode == CompilerMode.File)
            if (context.DynInitHelper != null)
            {
                call = context.DynInitHelper.ReduceDyn(dyn);
            }
            else
            {
                call = dyn;
            }

            if (returnType == typeof(void))
            {
                call = Expression.Block(call, Expression.Default(typeof(object)));
            }
            else
            {
                call = Expression.Convert(call, returnType);
            }

            if (sbParams.Count > 0)
            {
                // We have ref/out params.  Construct the complicated call;

                ParameterExpression   callValParam = Expression.Parameter(returnType, "__callVal");
                ParameterExpression[] allParams    = ClrExtensions.ArrayInsert <ParameterExpression>(callValParam, sbParams);

                call = Expression.Block(
                    returnType,
                    allParams,
                    Expression.Block(sbInits),
                    Expression.Assign(callValParam, call),
                    Expression.Block(sbTransfers),
                    callValParam);
            }

            return(call);
        }
        public static object CallMethod(string methodName, IList <Type> typeArgs, bool isStatic, Type t, object target, params object[] args)
        {
            Expression        targetExpr = isStatic ? Expression.Constant(t, typeof(Type)) : Expression.Constant(target);
            List <Expression> exprs      = new List <Expression>();

            foreach (object arg in args)
            {
                exprs.Add(Expression.Constant(arg));
            }

            Expression[] argExprs = ClrExtensions.ArrayInsert <Expression>(targetExpr, exprs);

            // TODO: Get rid of Default
            InvokeMemberBinder binder = new ClojureInvokeMemberBinder(ClojureContext.Default, methodName, argExprs.Length, isStatic);

            Expression dyn = Expression.Dynamic(binder, typeof(object), argExprs);

            LambdaExpression lambda = Expression.Lambda <clojure.lang.Compiler.ReplDelegate>(dyn);

            return(lambda.Compile().DynamicInvoke());
        }
Exemple #3
0
        private void EmitComplexCall(ObjExpr objx, CljILGen ilg)
        {
            // TOD: We have gotten rid of light-compile. Simplify this.
            // This is made more complex than I'd like by light-compiling.
            // Without light-compile, we could just:
            //   Emit the target expression
            //   Emit the arguments (and build up the parameter list for the lambda)
            //   Create the lambda, compile to a methodbuilder, and call it.
            // Light-compile forces us to
            //     create a lambda at the beginning because we must
            //     compile it to a delegate, to get the type
            //     write code to grab the delegate from a cache
            //     Then emit the target expression
            //          emit the arguments (but note we need already to have built the parameter list)
            //          Call the delegate
            //  Combined, this becomes
            //      Build the parameter list
            //      Build the dynamic call and lambda  (slightly different for light-compile vs full)
            //      if light-compile
            //          build the delegate
            //          cache it
            //          emit code to retrieve and cast it
            //       emit the target expression
            //       emit the args
            //       emit the call (slightly different for light compile vs full)
            //

            //  Build the parameter list

            List <ParameterExpression> paramExprs = new List <ParameterExpression>(_args.Count + 1);
            List <Type> paramTypes = new List <Type>(_args.Count + 1);

            Type targetType = GetTargetType();

            if (!targetType.IsPrimitive)
            {
                targetType = typeof(object);
            }

            paramExprs.Add(Expression.Parameter(targetType));
            paramTypes.Add(targetType);
            int i = 0;

            foreach (HostArg ha in _args)
            {
                i++;
                Expr e       = ha.ArgExpr;
                Type argType = e.HasClrType && e.ClrType != null && e.ClrType.IsPrimitive ? e.ClrType : typeof(object);

                switch (ha.ParamType)
                {
                case HostArg.ParameterType.ByRef:
                {
                    Type byRefType = argType.MakeByRefType();
                    paramExprs.Add(Expression.Parameter(byRefType, ha.LocalBinding.Name));
                    paramTypes.Add(byRefType);
                    break;
                }

                case HostArg.ParameterType.Standard:
                    if (argType.IsPrimitive && ha.ArgExpr is MaybePrimitiveExpr)
                    {
                        paramExprs.Add(Expression.Parameter(argType, ha.LocalBinding != null ? ha.LocalBinding.Name : "__temp_" + i));
                        paramTypes.Add(argType);
                    }
                    else
                    {
                        paramExprs.Add(Expression.Parameter(typeof(object), ha.LocalBinding != null ? ha.LocalBinding.Name : "__temp_" + i));
                        paramTypes.Add(typeof(object));
                    }
                    break;

                default:
                    throw Util.UnreachableCode();
                }
            }

            // Build dynamic call and lambda
            Type returnType           = HasClrType ? ClrType : typeof(object);
            InvokeMemberBinder binder = new ClojureInvokeMemberBinder(ClojureContext.Default, _methodName, paramExprs.Count, IsStaticCall);

            // This is what I want to do.
            //DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), paramExprs);
            // Unfortunately, the Expression.Dynamic method does not respect byRef parameters.
            // The workaround appears to be to roll your delegate type and then use Expression.MakeDynamic, as below.

            List <Type> callsiteParamTypes = new List <Type>(paramTypes.Count + 1);

            callsiteParamTypes.Add(typeof(System.Runtime.CompilerServices.CallSite));
            callsiteParamTypes.AddRange(paramTypes);
            Type dynType = Microsoft.Scripting.Generation.Snippets.Shared.DefineDelegate("__interop__", returnType, callsiteParamTypes.ToArray());

#if CLR2
            // Not covariant. Sigh.
            List <Expression> paramsAsExprs = new List <Expression>(paramExprs.Count);
            paramsAsExprs.AddRange(paramExprs.ToArray());
            DynamicExpression dyn = Expression.MakeDynamic(dynType, binder, paramsAsExprs);
#else
            DynamicExpression dyn = Expression.MakeDynamic(dynType, binder, paramExprs);
#endif
            LambdaExpression lambda;
            Type             delType;
            MethodBuilder    mbLambda;

            EmitDynamicCallPreamble(dyn, _spanMap, "__interop_" + _methodName + RT.nextID(), returnType, paramExprs, paramTypes.ToArray(), ilg, out lambda, out delType, out mbLambda);

            //  Emit target + args

            EmitTargetExpression(objx, ilg);

            i = 0;
            foreach (HostArg ha in _args)
            {
                i++;
                Expr e       = ha.ArgExpr;
                Type argType = e.HasClrType && e.ClrType != null && e.ClrType.IsPrimitive ? e.ClrType : typeof(object);

                switch (ha.ParamType)
                {
                case HostArg.ParameterType.ByRef:
                    EmitByRefArg(ha, objx, ilg);
                    break;

                case HostArg.ParameterType.Standard:
                    if (argType.IsPrimitive && ha.ArgExpr is MaybePrimitiveExpr)
                    {
                        ((MaybePrimitiveExpr)ha.ArgExpr).EmitUnboxed(RHC.Expression, objx, ilg);
                    }
                    else
                    {
                        ha.ArgExpr.Emit(RHC.Expression, objx, ilg);
                    }
                    break;

                default:
                    throw Util.UnreachableCode();
                }
            }

            EmitDynamicCallPostlude(lambda, delType, mbLambda, ilg);
        }