Example #1
0
 public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
 {
     return(new DynamicMetaObject(
                DynamicExpression.Dynamic(
                    _context.CreateInvokeBinder(CallInfo),
                    typeof(object),
                    GetArgs(target, args)
                    ),
                target.Restrictions.Merge(BindingRestrictions.Combine(args))
                ));
 }
Example #2
0
        internal static Delegate CreateDelegateForDynamicObject(LanguageContext context, object dynamicObject, Type delegateType, MethodInfo invoke)
        {
            PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, delegateType.ToString());

            Type returnType = invoke.ReturnType;

            ParameterInfo[] parameterInfos = invoke.GetParameters();

            var parameters = new List <ParameterExpression>();

            for (int i = 0; i < parameterInfos.Length; i++)
            {
                parameters.Add(Expression.Parameter(parameterInfos[i].ParameterType, "p" + i));
            }

            InvokeBinder  invokeBinder  = context.CreateInvokeBinder(new CallInfo(parameterInfos.Length));
            ConvertBinder convertBinder = (returnType != typeof(void)) ? context.CreateConvertBinder(returnType, explicitCast: true) : null;

            CallSite invokeSite     = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(MakeSiteSignature(parameterInfos)), invokeBinder);
            Type     invokeSiteType = invokeSite.GetType();

            Type     convertSiteType;
            CallSite convertSite;

            if (convertBinder != null)
            {
                convertSite     = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), returnType), convertBinder);
                convertSiteType = convertSite.GetType();
            }
            else
            {
                convertSiteType = null;
                convertSite     = null;
            }

            var locals = new List <ParameterExpression>();

            ParameterExpression invokeSiteVar  = Expression.Parameter(invokeSiteType, "site");
            ParameterExpression convertSiteVar = null;

            var args = new List <Expression>();

            args.Add(invokeSiteVar);
            args.Add(Expression.Constant(dynamicObject));

            int strongBoxVarsStart = locals.Count;

            for (int i = 0; i < parameterInfos.Length; i++)
            {
                if (parameterInfos[i].ParameterType.IsByRef)
                {
                    var argType = parameterInfos[i].ParameterType;

                    Type elementType  = argType.GetElementType();
                    Type concreteType = typeof(StrongBox <>).MakeGenericType(elementType);

                    var strongBox = Expression.Parameter(concreteType, "box" + i);
                    locals.Add(strongBox);

                    args.Add(
                        Expression.Assign(
                            strongBox,
                            Expression.New(
                                concreteType.GetConstructor(new Type[] { elementType }),
                                parameters[i]
                                )
                            )
                        );
                }
                else
                {
                    args.Add(parameters[i]);
                }
            }

            int strongBoxVarsEnd = locals.Count;

            Expression invocation = Expression.Invoke(
                Expression.Field(
                    Expression.Assign(
                        invokeSiteVar,
                        Expression.Convert(Expression.Constant(invokeSite), invokeSiteType)
                        ),
                    invokeSiteType.GetDeclaredField("Target")
                    ),
                args
                );

            if (convertBinder != null)
            {
                convertSiteVar = Expression.Parameter(convertSiteType, "convertSite");

                invocation = Expression.Invoke(
                    Expression.Field(
                        Expression.Assign(
                            convertSiteVar,
                            Expression.Convert(Expression.Constant(convertSite), convertSiteType)
                            ),
                        convertSiteType.GetDeclaredField("Target")
                        ),
                    convertSiteVar,
                    invocation
                    );
            }

            locals.Add(invokeSiteVar);
            if (convertSiteVar != null)
            {
                locals.Add(convertSiteVar);
            }

            Expression body;

            // copy back from StrongBox.Value
            if (strongBoxVarsEnd > strongBoxVarsStart)
            {
                var block = new Expression[1 + strongBoxVarsEnd - strongBoxVarsStart + 1];

                var resultVar = Expression.Parameter(invocation.Type, "result");
                locals.Add(resultVar);

                int b = 0;
                int l = strongBoxVarsStart;

                // values of strong boxes are initialized in invocation expression:
                block[b++] = Expression.Assign(resultVar, invocation);

                for (int i = 0; i < parameterInfos.Length; i++)
                {
                    if (parameterInfos[i].ParameterType.IsByRef)
                    {
                        var local = locals[l++];
                        block[b++] = Expression.Assign(
                            parameters[i],
                            Expression.Field(local, local.Type.GetDeclaredField("Value"))
                            );
                    }
                }

                block[b++] = resultVar;

                Debug.Assert(l == strongBoxVarsEnd);
                Debug.Assert(b == block.Length);

                body = Expression.Block(locals, block);
            }
            else
            {
                body = Expression.Block(locals, invocation);
            }

            var lambda = Expression.Lambda(delegateType, body, "_Scripting_", parameters);

            return(lambda.Compile());
        }
Example #3
0
 /// <summary>
 /// Calls the provided object with the given parameters and returns the result.
 ///
 /// The prefered way of calling objects is to convert the object to a strongly typed delegate
 /// using the ConvertTo methods and then invoking that delegate.
 /// </summary>
 public object Invoke(object obj, params object[] parameters)
 {
     return(GetInvoker(parameters.Length)(this, _lc.CreateInvokeBinder(new CallInfo(parameters.Length)), obj, parameters));
 }
        /// <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);
        }