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