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