protected override Expression VisitDynamic(DynamicExpression node) { Type siteType = typeof(CallSite <>).MakeGenericType(node.DelegateType); // Rewite call site as constant var siteExpr = VisitConstant(Expression.Constant(DynamicSiteHelpers.MakeSite(node.Binder, siteType))); // Rewrite all of the arguments var args = Visit(node.Arguments); var siteVar = Expression.Variable(siteExpr.Type, "$site"); // ($site = siteExpr).Target.Invoke($site, *args) return(Expression.Block( new [] { siteVar }, Expression.Call( Expression.Field( Expression.Assign(siteVar, siteExpr), siteType.GetField("Target") ), node.DelegateType.GetMethod("Invoke"), ArrayUtils.Insert(siteVar, args) ) )); }
/// <summary> /// Generates stub to receive the CLR call and then call the dynamic language code. /// </summary> private object[] EmitClrCallStub(ILGen cg) { List <ReturnFixer> fixers = new List <ReturnFixer>(0); ArgumentInfo[] args = new ArgumentInfo[_parameters.Length]; for (int i = 0; i < args.Length; i++) { args[i] = Expression.PositionalArg(i); } ConvertBinder convert = _context.CreateConvertBinder(_returnType, true); InvokeBinder action = _context.CreateInvokeBinder(args); // Create strongly typed return type from the site. // This will, among other things, generate tighter code. Type[] siteTypes = MakeSiteSignature(); Type siteType = DynamicSiteHelpers.MakeCallSiteType(siteTypes); CallSite callSite = DynamicSiteHelpers.MakeSite(action, siteType); Type convertSiteType = null; CallSite convertSite = null; if (_returnType != typeof(void)) { convertSiteType = DynamicSiteHelpers.MakeCallSiteType(typeof(object), _returnType); convertSite = DynamicSiteHelpers.MakeSite(convert, convertSiteType); } // build up constants array object[] constants = new object[] { TargetPlaceHolder, callSite, convertSite }; const int TargetIndex = 0, CallSiteIndex = 1, ConvertSiteIndex = 2; LocalBuilder convertSiteLocal = null; FieldInfo convertTarget = null; if (_returnType != typeof(void)) { // load up the conversesion logic on the stack convertSiteLocal = cg.DeclareLocal(convertSiteType); EmitConstantGet(cg, ConvertSiteIndex, convertSiteType); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Stloc, convertSiteLocal); convertTarget = convertSiteType.GetField("Target"); cg.EmitFieldGet(convertTarget); cg.Emit(OpCodes.Ldloc, convertSiteLocal); } // load up the invoke logic on the stack LocalBuilder site = cg.DeclareLocal(siteType); EmitConstantGet(cg, CallSiteIndex, siteType); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Stloc, site); FieldInfo target = siteType.GetField("Target"); cg.EmitFieldGet(target); cg.Emit(OpCodes.Ldloc, site); EmitConstantGet(cg, TargetIndex, typeof(object)); for (int i = 0; i < _parameters.Length; i++) { if (_parameters[i].ParameterType.IsByRef) { ReturnFixer rf = ReturnFixer.EmitArgument(cg, i + 1, _parameters[i].ParameterType); if (rf != null) { fixers.Add(rf); } } else { cg.EmitLoadArg(i + 1); } } // emit the invoke for the call cg.EmitCall(target.FieldType, "Invoke"); // emit the invoke for the convert if (_returnType == typeof(void)) { cg.Emit(OpCodes.Pop); } else { cg.EmitCall(convertTarget.FieldType, "Invoke"); } // fixup any references foreach (ReturnFixer rf in fixers) { rf.FixReturn(cg); } cg.Emit(OpCodes.Ret); return(constants); }