예제 #1
0
        public DelegateInfo(LanguageContext context, Type returnType, Type[] parameters)
        {
            Assert.NotNull(returnType);
            Assert.NotNullItems(parameters);

            _returnType     = returnType;
            _parameterTypes = parameters;

            PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, ToString());

            if (_returnType != typeof(void))
            {
                _convertBinder = context.CreateConvertBinder(_returnType, true);
            }

            _invokeBinder = context.CreateInvokeBinder(new CallInfo(_parameterTypes.Length));

            Type[] delegateParams = new Type[1 + _parameterTypes.Length];
            delegateParams[0] = typeof(object[]);
            for (int i = 0; i < _parameterTypes.Length; i++)
            {
                delegateParams[1 + i] = _parameterTypes[i];
            }

            EmitClrCallStub(returnType, delegateParams, out _method);
        }
예제 #2
0
        internal DelegateInfo(LanguageContext context, Type returnType, ParameterInfo[] parameters)
        {
            Assert.NotNull(returnType);
            Assert.NotNullItems(parameters);

            _returnType = returnType;
            _parameters = parameters;

            PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, ToString());

            if (_returnType != typeof(void))
            {
                _convertBinder = context.CreateConvertBinder(_returnType, true);
            }

            _invokeBinder = context.CreateInvokeBinder(new CallInfo(_parameters.Length));

            Type[] delegateParams = new Type[_parameters.Length];
            for (int i = 0; i < _parameters.Length; i++)
            {
                delegateParams[i] = _parameters[i].ParameterType;
            }

            // Create the method with a special name so the langauge compiler knows that method's stack frame is not visible
            DynamicILGen cg = Snippets.Shared.CreateDynamicMethod("_Scripting_", _returnType, ArrayUtils.Insert(typeof(object[]), delegateParams), false);

            // Emit the stub
            _constants = EmitClrCallStub(cg);
            _method    = cg.Finish();
        }
예제 #3
0
        /// <summary>
        /// Gets the member name from the object obj and converts it to the type T. The conversion will be explicit or implicit
        /// depending on what the langauge prefers. Throws an exception if the member does not exist, is write-only, or cannot be converted.
        /// </summary>
        public T GetMember <T>(object obj, string name, bool ignoreCase)
        {
            CallSite <Func <CallSite, object, T> >      convertSite = GetOrCreateSite <object, T>(_lc.CreateConvertBinder(typeof(T), null));
            CallSite <Func <CallSite, object, object> > site        = GetOrCreateSite <object, object>(_lc.CreateGetMemberBinder(name, ignoreCase));

            return(convertSite.Target(convertSite, site.Target(site, obj)));
        }
예제 #4
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());
        }
예제 #5
0
        /// <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);
        }