Exemple #1
0
        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);
        }