예제 #1
0
        private Func <CallSite, TSelfType, CodeContext, object> MakeGetMemberTarget <TSelfType>(string name, object target, CodeContext context)
        {
            Type type = CompilerHelpers.GetType(target);

            // needed for GetMember call until DynamicAction goes away
            if (typeof(TypeTracker).IsAssignableFrom(type))
            {
                // no fast path for TypeTrackers
                PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast TypeTracker");
                return(null);
            }

            MemberGroup members = Context.Binder.GetMember(MemberRequestKind.Get, type, name);

            if (members.Count == 0 && type.IsInterface())
            {
                // all interfaces have object members
                type    = typeof(object);
                members = Context.Binder.GetMember(MemberRequestKind.Get, type, name);
            }

            if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type))
            {
                // no fast path for strong box access
                PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast StrongBox");
                return(null);
            }

            MethodInfo getMem = Context.Binder.GetMethod(type, "GetCustomMember");

            if (getMem != null && getMem.IsSpecialName)
            {
                // no fast path for custom member access
                PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetCustomMember " + type);
                return(null);
            }

            Expression   error;
            TrackerTypes memberType = Context.Binder.GetMemberType(members, out error);

            if (error == null)
            {
                PythonType argType  = DynamicHelpers.GetPythonTypeFromType(type);
                bool       isHidden = argType.IsHiddenMember(name);
                if (isHidden)
                {
                    PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast FilteredMember " + memberType);
                    return(null);
                }

                switch (memberType)
                {
                case TrackerTypes.TypeGroup:
                case TrackerTypes.Type:
                    object typeObj;
                    if (members.Count == 1)
                    {
                        typeObj = DynamicHelpers.GetPythonTypeFromType(((TypeTracker)members[0]).Type);
                    }
                    else
                    {
                        TypeTracker typeTracker = (TypeTracker)members[0];
                        for (int i = 1; i < members.Count; i++)
                        {
                            typeTracker = TypeGroup.UpdateTypeEntity(typeTracker, (TypeTracker)members[i]);
                        }
                        typeObj = typeTracker;
                    }

                    return(new FastTypeGet <TSelfType>(type, typeObj).GetTypeObject);

                case TrackerTypes.Method:
                    PythonTypeSlot slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding);
                    if (slot is BuiltinMethodDescriptor)
                    {
                        return(new FastMethodGet <TSelfType>(type, (BuiltinMethodDescriptor)slot).GetMethod);
                    }
                    else if (slot is BuiltinFunction)
                    {
                        return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetRetSlot);
                    }
                    return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetBindSlot);

                case TrackerTypes.Event:
                    if (members.Count == 1 && !((EventTracker)members[0]).IsStatic)
                    {
                        slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding);
                        return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(((EventTracker)members[0]).DeclaringType)).GetBindSlot);
                    }
                    PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Event " + members.Count + " " + ((EventTracker)members[0]).IsStatic);
                    return(null);

                case TrackerTypes.Property:
                    if (members.Count == 1)
                    {
                        PropertyTracker pt = (PropertyTracker)members[0];
                        if (!pt.IsStatic && pt.GetIndexParameters().Length == 0)
                        {
                            MethodInfo      prop = pt.GetGetMethod();
                            ParameterInfo[] parameters;

                            if (prop != null && (parameters = prop.GetParameters()).Length == 0)
                            {
                                if (prop.ReturnType == typeof(bool))
                                {
                                    return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyBool);
                                }
                                else if (prop.ReturnType == typeof(int))
                                {
                                    return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyInt);
                                }
                                else
                                {
                                    return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetProperty);
                                }
                            }
                        }
                    }
                    PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Property " + members.Count + " " + ((PropertyTracker)members[0]).IsStatic);
                    return(null);

                case TrackerTypes.All:
                    getMem = Context.Binder.GetMethod(type, "GetBoundMember");
                    if (getMem != null && getMem.IsSpecialName)
                    {
                        PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetBoundMember " + type);
                        return(null);
                    }

                    if (members.Count == 0)
                    {
                        // we don't yet support fast bindings to extension methods
                        members = context.ModuleContext.ExtensionMethods.GetBinder(_context).GetMember(MemberRequestKind.Get, type, name);
                        if (members.Count == 0)
                        {
                            if (IsNoThrow)
                            {
                                return(new FastErrorGet <TSelfType>(type, name, context.ModuleContext.ExtensionMethods).GetErrorNoThrow);
                            }
                            else if (SupportsLightThrow)
                            {
                                return(new FastErrorGet <TSelfType>(type, name, context.ModuleContext.ExtensionMethods).GetErrorLightThrow);
                            }
                            else
                            {
                                return(new FastErrorGet <TSelfType>(type, name, context.ModuleContext.ExtensionMethods).GetError);
                            }
                        }
                    }
                    return(null);

                default:
                    PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast " + memberType);
                    return(null);
                }
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                foreach (MemberTracker mi in members)
                {
                    if (sb.Length != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(mi.MemberType);
                    sb.Append(" : ");
                    sb.Append(mi.ToString());
                }

                return(new FastErrorGet <TSelfType>(type, sb.ToString(), context.ModuleContext.ExtensionMethods).GetAmbiguous);
            }
        }