Inheritance: System.Dynamic.InvokeMemberBinder, IExpressionSerializable, IClojureSite
Example #1
0
        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();
        }
Example #2
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);
        }
Example #3
0
        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;
        }