示例#1
0
        /////////////////////////////////////////////////////////////////////////////////

        private static BindingRestrictions DeduceArgumentRestriction(
            int parameterIndex,
            ICSharpInvokeOrInvokeMemberBinder callPayload,
            DynamicMetaObject argument,
            CSharpArgumentInfo info)
        {
            // Here we deduce what predicates the DLR can apply to future calls in order to
            // determine whether to use the previously-computed-and-cached delegate, or
            // whether we need to bind the site again. Ideally we would like the
            // predicate to be as broad as is possible; if we can re-use analysis based
            // solely on the type of the argument, that is preferable to re-using analysis
            // based on object identity with a previously-analyzed argument.

            // The times when we need to restrict re-use to a particular instance, rather
            // than its type, are:
            //
            // * if the argument is a null reference then we have no type information.
            //
            // * if we are making a static call then the first argument is
            //   going to be a Type object. In this scenario we should always check
            //   for a specific Type object rather than restricting to the Type type.
            //
            // * if the argument was dynamic at compile time and it is a dynamic proxy
            //   object that the runtime manages, such as COM RCWs and transparent
            //   proxies.
            //
            // ** there is also a case for constant values (such as literals) to use
            //    something like value restrictions, and that is accomplished in Bind().

            bool useValueRestriction =
                argument.Value == null ||
                IsTypeOfStaticCall(parameterIndex, callPayload) ||
                IsDynamicallyTypedRuntimeProxy(argument, info);

            return(useValueRestriction ?
                   BindingRestrictions.GetInstanceRestriction(argument.Expression, argument.Value) :
                   BindingRestrictions.GetTypeRestriction(argument.Expression, argument.RuntimeType));
        }
示例#2
0
        internal static DynamicMetaObject Bind(
            DynamicMetaObjectBinder action,
            RuntimeBinder binder,
            IEnumerable <DynamicMetaObject> args,
            IEnumerable <CSharpArgumentInfo> arginfos,
            DynamicMetaObject onBindingError)
        {
            List <Expression>   parameters   = new List <Expression>();
            BindingRestrictions restrictions = BindingRestrictions.Empty;
            ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder;
            ParameterExpression tempForIncrement          = null;
            IEnumerator <CSharpArgumentInfo> arginfosEnum = arginfos == null ? null : arginfos.GetEnumerator();

            int index = 0;

            foreach (DynamicMetaObject o in args)
            {
                // Our contract with the DLR is such that we will not enter a bind unless we have
                // values for the meta-objects involved.

                if (!o.HasValue)
                {
                    Debug.Assert(false, "The runtime binder is being asked to bind a metaobject without a value");
                    throw Error.InternalCompilerError();
                }
                CSharpArgumentInfo info = null;
                if (arginfosEnum != null && arginfosEnum.MoveNext())
                {
                    info = arginfosEnum.Current;
                }

                if (index == 0 && IsIncrementOrDecrementActionOnLocal(action))
                {
                    // We have an inc or a dec operation. Insert the temp local instead.
                    //
                    // We need to do this because for value types, the object will come
                    // in boxed, and we'd need to unbox it to get the original type in order
                    // to increment. The only way to do that is to create a new temporary.
                    tempForIncrement = Expression.Variable(o.Value != null ? o.Value.GetType() : typeof(object), "t0");
                    parameters.Add(tempForIncrement);
                }
                else
                {
                    parameters.Add(o.Expression);
                }

                BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info);
                restrictions = restrictions.Merge(r);

                // Here we check the argument info. If the argument info shows that the current argument
                // is a literal constant, then we also add an instance restriction on the value of
                // the constant.
                if (info != null && info.LiteralConstant)
                {
                    if ((o.Value is float && float.IsNaN((float)o.Value)) ||
                        o.Value is double && double.IsNaN((double)o.Value))
                    {
                        // We cannot create an equality restriction for NaN, because equality is implemented
                        // in such a way that NaN != NaN and the rule we make would be unsatisfiable.
                    }
                    else
                    {
                        Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type));
                        r            = BindingRestrictions.GetExpressionRestriction(e);
                        restrictions = restrictions.Merge(r);
                    }
                }

                ++index;
            }

            // Get the bound expression.
            try
            {
                DynamicMetaObject deferredBinding;
                Expression        expression = binder.Bind(action, parameters, args.ToArray(), out deferredBinding);

                if (deferredBinding != null)
                {
                    expression   = ConvertResult(deferredBinding.Expression, action);
                    restrictions = deferredBinding.Restrictions.Merge(restrictions);
                    return(new DynamicMetaObject(expression, restrictions));
                }

                if (tempForIncrement != null)
                {
                    // If we have a ++ or -- payload, we need to do some temp rewriting.
                    // We rewrite to the following:
                    //
                    // temp = (type)o;
                    // temp++;
                    // o = temp;
                    // return o;

                    DynamicMetaObject arg0 = Enumerable.First(args);

                    Expression assignTemp = Expression.Assign(
                        tempForIncrement,
                        Expression.Convert(arg0.Expression, arg0.Value.GetType()));
                    Expression assignResult = Expression.Assign(
                        arg0.Expression,
                        Expression.Convert(tempForIncrement, arg0.Expression.Type));
                    List <Expression> expressions = new List <Expression>();

                    expressions.Add(assignTemp);
                    expressions.Add(expression);
                    expressions.Add(assignResult);

                    expression = Expression.Block(new ParameterExpression[] { tempForIncrement }, expressions);
                }

                expression = ConvertResult(expression, action);

                return(new DynamicMetaObject(expression, restrictions));
            }
            catch (RuntimeBinderException e)
            {
                if (onBindingError != null)
                {
                    return(onBindingError);
                }

                return(new DynamicMetaObject(
                           Expression.Throw(
                               Expression.New(
                                   typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }),
                                   Expression.Constant(e.Message)
                                   ),
                               GetTypeForErrorMetaObject(action, args.FirstOrDefault())
                               ),
                           restrictions
                           ));
            }
        }
示例#3
0
        /////////////////////////////////////////////////////////////////////////////////

        private static bool IsTypeOfStaticCall(
            int parameterIndex,
            ICSharpInvokeOrInvokeMemberBinder callPayload)
        {
            return(parameterIndex == 0 && callPayload != null && callPayload.StaticCall);
        }
示例#4
0
        internal static DynamicMetaObject Bind(
            ICSharpBinder action,
            RuntimeBinder binder,
            DynamicMetaObject[] args,
            IEnumerable <CSharpArgumentInfo> arginfos,
            DynamicMetaObject onBindingError)
        {
            Expression[]        parameters   = new Expression[args.Length];
            BindingRestrictions restrictions = BindingRestrictions.Empty;
            ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder;
            ParameterExpression tempForIncrement          = null;
            IEnumerator <CSharpArgumentInfo> arginfosEnum = (arginfos ?? Array.Empty <CSharpArgumentInfo>()).GetEnumerator();

            for (int index = 0; index < args.Length; ++index)
            {
                DynamicMetaObject o = args[index];
                // Our contract with the DLR is such that we will not enter a bind unless we have
                // values for the meta-objects involved.

                Debug.Assert(o.HasValue);

                CSharpArgumentInfo info = arginfosEnum.MoveNext() ? arginfosEnum.Current : null;

                if (index == 0 && IsIncrementOrDecrementActionOnLocal(action))
                {
                    // We have an inc or a dec operation. Insert the temp local instead.
                    //
                    // We need to do this because for value types, the object will come
                    // in boxed, and we'd need to unbox it to get the original type in order
                    // to increment. The only way to do that is to create a new temporary.
                    object value = o.Value;
                    tempForIncrement = Expression.Variable(value != null ? value.GetType() : typeof(object), "t0");
                    parameters[0]    = tempForIncrement;
                }
                else
                {
                    parameters[index] = o.Expression;
                }

                BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info);
                restrictions = restrictions.Merge(r);

                // Here we check the argument info. If the argument info shows that the current argument
                // is a literal constant, then we also add an instance restriction on the value of
                // the constant.
                if (info != null && info.LiteralConstant)
                {
                    if (o.Value is double && double.IsNaN((double)o.Value))
                    {
                        MethodInfo isNaN = s_DoubleIsNaN ?? (s_DoubleIsNaN = typeof(double).GetMethod("IsNaN"));
                        Expression e     = Expression.Call(null, isNaN, o.Expression);
                        restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e));
                    }
                    else if (o.Value is float && float.IsNaN((float)o.Value))
                    {
                        MethodInfo isNaN = s_SingleIsNaN ?? (s_SingleIsNaN = typeof(float).GetMethod("IsNaN"));
                        Expression e     = Expression.Call(null, isNaN, o.Expression);
                        restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e));
                    }
                    else
                    {
                        Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type));
                        r            = BindingRestrictions.GetExpressionRestriction(e);
                        restrictions = restrictions.Merge(r);
                    }
                }
            }

            // Get the bound expression.
            try
            {
                Expression expression = binder.Bind(action, parameters, args, out DynamicMetaObject deferredBinding);

                if (deferredBinding != null)
                {
                    expression   = ConvertResult(deferredBinding.Expression, action);
                    restrictions = deferredBinding.Restrictions.Merge(restrictions);
                    return(new DynamicMetaObject(expression, restrictions));
                }

                if (tempForIncrement != null)
                {
                    // If we have a ++ or -- payload, we need to do some temp rewriting.
                    // We rewrite to the following:
                    //
                    // temp = (type)o;
                    // temp++;
                    // o = temp;
                    // return o;

                    DynamicMetaObject arg0 = args[0];

                    expression = Expression.Block(
                        new[] { tempForIncrement },
                        Expression.Assign(tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())),
                        expression,
                        Expression.Assign(arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type)));
                }

                expression = ConvertResult(expression, action);

                return(new DynamicMetaObject(expression, restrictions));
            }
            catch (RuntimeBinderException e)
            {
                if (onBindingError != null)
                {
                    return(onBindingError);
                }

                return(new DynamicMetaObject(
                           Expression.Throw(
                               Expression.New(
                                   typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }),
                                   Expression.Constant(e.Message)
                                   ),
                               GetTypeForErrorMetaObject(action, args)
                               ),
                           restrictions
                           ));
            }
        }
示例#5
0
        /////////////////////////////////////////////////////////////////////////////////

        private EXPR BindCall(
            ICSharpInvokeOrInvokeMemberBinder payload,
            EXPR callingObject,
            ArgumentObject[] arguments,
            Dictionary<int, LocalVariableSymbol> dictionary)
        {
            if (payload is InvokeBinder && !callingObject.type.isDelegateType())
            {
                throw Error.BindInvokeFailedNonDelegate();
            }

            EXPR pResult = null;
            int arity = payload.TypeArguments != null ? payload.TypeArguments.Count : 0;
            MemberLookup mem = new MemberLookup();

            Debug.Assert(_bindingContext.ContextForMemberLookup() != null);
            SymWithType swt = _symbolTable.LookupMember(
                    payload.Name,
                    callingObject,
                    _bindingContext.ContextForMemberLookup(),
                    arity,
                    mem,
                    (payload.Flags & CSharpCallFlags.EventHookup) != 0,
                    true);
            if (swt == null)
            {
                mem.ReportErrors();
                Debug.Assert(false, "Why didn't member lookup report an error?");
            }

            if (swt.Sym.getKind() != SYMKIND.SK_MethodSymbol)
            {
                Debug.Assert(false, "Unexpected type returned from lookup");
                throw Error.InternalCompilerError();
            }

            // At this point, we're set up to do binding. We need to do the following:
            //
            // 1) Create the EXPRLOCALs for the arguments, linking them to the local
            //    variable symbols defined above.
            // 2) Create the EXPRMEMGRP for the call and the EXPRLOCAL for the object
            //    of the call, and link the correct local variable symbol as above.
            // 3) Do overload resolution to get back an EXPRCALL.
            //
            // Our caller takes care of the rest.

            // First we need to check the sym that we got back. If we got back a static 
            // method, then we may be in the situation where the user called the method
            // via a simple name call through the phantom overload. If thats the case,
            // then we want to sub in a type instead of the object.
            EXPRMEMGRP memGroup = CreateMemberGroupEXPR(payload.Name, payload.TypeArguments, callingObject, swt.Sym.getKind());
            if ((payload.Flags & CSharpCallFlags.SimpleNameCall) != 0)
            {
                callingObject.flags |= EXPRFLAG.EXF_SIMPLENAME;
            }

            if ((payload.Flags & CSharpCallFlags.EventHookup) != 0)
            {
                mem = new MemberLookup();
                SymWithType swtEvent = _symbolTable.LookupMember(
                        payload.Name.Split('_')[1],
                        callingObject,
                        _bindingContext.ContextForMemberLookup(),
                        arity,
                        mem,
                        (payload.Flags & CSharpCallFlags.EventHookup) != 0,
                        true);
                if (swtEvent == null)
                {
                    mem.ReportErrors();
                    Debug.Assert(false, "Why didn't member lookup report an error?");
                }

                CType eventCType = null;
                if (swtEvent.Sym.getKind() == SYMKIND.SK_FieldSymbol)
                {
                    eventCType = swtEvent.Field().GetType();
                }
                else if (swtEvent.Sym.getKind() == SYMKIND.SK_EventSymbol)
                {
                    eventCType = swtEvent.Event().type;
                }

                Type eventType = SymbolLoader.GetTypeManager().SubstType(eventCType, swtEvent.Ats).AssociatedSystemType;

                if (eventType != null)
                {
                    // If we have an event hookup, first find the event itself.
                    BindImplicitConversion(new ArgumentObject[] { arguments[1] }, eventType, dictionary, false);
                }
                memGroup.flags &= ~EXPRFLAG.EXF_USERCALLABLE;

                if (swtEvent.Sym.getKind() == SYMKIND.SK_EventSymbol && swtEvent.Event().IsWindowsRuntimeEvent)
                {
                    return BindWinRTEventAccessor(
                                    new EventWithType(swtEvent.Event(), swtEvent.Ats),
                                    callingObject,
                                    arguments,
                                    dictionary,
                                    payload.Name.StartsWith("add_", StringComparison.Ordinal)); //isAddAccessor?
                }
            }

            // Check if we have a potential call to an indexed property accessor.
            // If so, we'll flag overload resolution to let us call non-callables.
            if ((payload.Name.StartsWith("set_", StringComparison.Ordinal) && swt.Sym.AsMethodSymbol().Params.Size > 1) ||
                (payload.Name.StartsWith("get_", StringComparison.Ordinal) && swt.Sym.AsMethodSymbol().Params.Size > 0))
            {
                memGroup.flags &= ~EXPRFLAG.EXF_USERCALLABLE;
            }

            pResult = _binder.BindMethodGroupToArguments(// Tree
                BindingFlag.BIND_RVALUEREQUIRED | BindingFlag.BIND_STMTEXPRONLY, memGroup, CreateArgumentListEXPR(arguments, dictionary, 1, arguments.Length));

            // If overload resolution failed, throw an error.
            if (pResult == null || !pResult.isOK())
            {
                throw Error.BindCallFailedOverloadResolution();
            }
            CheckForConditionalMethodError(pResult);

            return ReorderArgumentsForNamedAndOptional(callingObject, pResult);
        }
示例#6
0
        /////////////////////////////////////////////////////////////////////////////////

        private EXPR CreateCallingObjectForCall(
            ICSharpInvokeOrInvokeMemberBinder payload,
            ArgumentObject[] arguments,
            Dictionary<int, LocalVariableSymbol> dictionary)
        {
            // Here we have a regular call, so create the calling object off of the first
            // parameter and pass it through.
            EXPR callingObject;
            if (payload.StaticCall)
            {
                if (arguments[0].Value == null || !(arguments[0].Value is Type))
                {
                    Debug.Assert(false, "Cannot make static call without specifying a type");
                    throw Error.InternalCompilerError();
                }
                Type t = arguments[0].Value as Type;
                callingObject = _exprFactory.CreateClass(_symbolTable.GetCTypeFromType(t), null, t.GetTypeInfo().ContainsGenericParameters ?
                        _exprFactory.CreateTypeArguments(SymbolLoader.getBSymmgr().AllocParams(_symbolTable.GetCTypeArrayFromTypes(t.GetGenericArguments())), null) : null);
            }
            else
            {
                // If we have a null argument, just bail and throw.
                if (!arguments[0].Info.UseCompileTimeType && arguments[0].Value == null)
                {
                    throw Error.NullReferenceOnMemberException();
                }

                callingObject = _binder.mustConvert(
                    CreateArgumentEXPR(arguments[0], dictionary[0]),
                    _symbolTable.GetCTypeFromType(arguments[0].Type));

                if (arguments[0].Type.GetTypeInfo().IsValueType && callingObject.isCAST())
                {
                    // If we have a struct type, unbox it.
                    callingObject.flags |= EXPRFLAG.EXF_UNBOXRUNTIME;
                }
            }
            return callingObject;
        }