private void EmitComplexCall(RHC rhc, ObjExpr objx, CljILGen ilg) { // See the notes on MethodExpr.EmitComplexCall on why this is so complicated List<ParameterExpression> paramExprs = new List<ParameterExpression>(_args.Count + 1); List<Type> paramTypes = new List<Type>(_args.Count + 1); paramExprs.Add(Expression.Parameter(typeof(Type))); paramTypes.Add(typeof(Type)); 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); CreateInstanceBinder binder = new ClojureCreateInstanceBinder(ClojureContext.Default, _args.Count); #if CLR2 // Not covariant. Sigh. List<Expression> paramsAsExprs = new List<Expression>(paramExprs.Count); paramsAsExprs.AddRange(paramExprs.ToArray()); DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), paramsAsExprs); #else DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), paramExprs); #endif LambdaExpression lambda; Type delType; MethodBuilder mbLambda; MethodExpr.EmitDynamicCallPreamble(dyn, _spanMap, "__interop_ctor_" + 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: MethodExpr.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(); } } MethodExpr.EmitDynamicCallPostlude(lambda, delType, mbLambda, ilg); }
// TODO: See if it is worth removing the code duplication with MethodExp.GenDlr. private Expression GenerateComplexCall(RHC rhc, 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>(); MethodExpr.GenerateComplexArgList(objx, context, _args, out exprs, out sbParams, out sbInits, out sbTransfers); Expression[] argExprs = ClrExtensions.ArrayInsert<Expression>(target, exprs); Type returnType = this.ClrType; Type stubType = Compiler.CompileStubOrigClassVar.isBound ? (Type)Compiler.CompileStubOrigClassVar.deref() : null; if (returnType == stubType) returnType = objx.BaseType; // TODO: get rid of Default CreateInstanceBinder binder = new ClojureCreateInstanceBinder(ClojureContext.Default,_args.Count); DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), argExprs); // I'd like to use returnType in place of typeof(object) in the previous, // But I can't override ReturnType in DefaultCreateInstanceBinder and this causes an error. // Look for the conversion below. //if (context.Mode == CompilerMode.File) if (context.DynInitHelper != null) call = context.DynInitHelper.ReduceDyn(dyn); else call = dyn; 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; }