Ejemplo n.º 1
0
        private void Cache(bool hasObject, CallbackArguments args, IOverloadableMemberDescriptor bestOverload)
        {
            int lowestHits          = int.MaxValue;
            OverloadCacheItem found = null;

            for (int i = 0; i < m_Cache.Length; i++)
            {
                if (m_Cache[i] == null)
                {
                    found = new OverloadCacheItem
                    {
                        ArgsDataType = new List <DataType>(), ArgsUserDataType = new List <Type>()
                    };
                    m_Cache[i] = found;
                    break;
                }

                if (m_Cache[i].HitIndexAtLastHit < lowestHits)
                {
                    lowestHits = m_Cache[i].HitIndexAtLastHit;
                    found      = m_Cache[i];
                }
            }

            if (found == null)
            {
                // overflow..
                m_Cache = new OverloadCacheItem[CACHE_SIZE];
                found   = new OverloadCacheItem
                {
                    ArgsDataType = new List <DataType>(), ArgsUserDataType = new List <Type>()
                };
                m_Cache[0]  = found;
                m_CacheHits = 0;
            }

            found.Method            = bestOverload;
            found.HitIndexAtLastHit = ++m_CacheHits;
            found.ArgsDataType.Clear();
            found.HasObject = hasObject;

            for (int i = 0; i < args.Count; i++)
            {
                found.ArgsDataType.Add(args[i].Type);

                if (args[i].Type == DataType.UserData)
                {
                    found.ArgsUserDataType.Add(args[i].UserData.Descriptor.Type);
                }
                else
                {
                    found.ArgsUserDataType.Add(null);
                }
            }
        }
Ejemplo n.º 2
0
        private void AddMemberTo(Dictionary <string, IMemberDescriptor> members, string name, IMemberDescriptor desc)
        {
            IOverloadableMemberDescriptor odesc = desc as IOverloadableMemberDescriptor;

            if (odesc != null)
            {
                if (members.ContainsKey(name))
                {
                    OverloadedMethodMemberDescriptor overloads = members[name] as OverloadedMethodMemberDescriptor;

                    if (overloads != null)
                    {
                        overloads.AddOverload(odesc);
                    }
                    else
                    {
                        throw new ArgumentException(string.Format("Multiple members named {0} are being added to type {1} and one or more of these members do not support overloads.", name, this.Type.FullName));
                    }
                }
                else
                {
                    members.Add(name, new OverloadedMethodMemberDescriptor(name, this.Type, odesc));
                }
            }
            else
            {
                if (members.ContainsKey(name))
                {
                    throw new ArgumentException(string.Format("Multiple members named {0} are being added to type {1} and one or more of these members do not support overloads.", name, this.Type.FullName));
                }
                else
                {
                    members.Add(name, desc);
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="OverloadedMethodMemberDescriptor" /> class.
 /// </summary>
 /// <param name="name">The name.</param>
 /// <param name="declaringType">The declaring type.</param>
 /// <param name="descriptor">The descriptor of the first overloaded method.</param>
 public OverloadedMethodMemberDescriptor(string name, Type declaringType, IOverloadableMemberDescriptor descriptor)
     : this(name, declaringType)
 {
     m_Overloads.Add(descriptor);
 }
        /// <summary>
        /// Calculates the score for the overload.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="args">The arguments.</param>
        /// <param name="method">The method.</param>
        /// <param name="isExtMethod">if set to <c>true</c>, is an extension method.</param>
        /// <returns></returns>
        private int CalcScoreForOverload(ScriptExecutionContext context, CallbackArguments args, IOverloadableMemberDescriptor method, bool isExtMethod)
        {
            int  totalScore  = ScriptToClrConversions.WEIGHT_EXACT_MATCH;
            int  argsBase    = args.IsMethodCall ? 1 : 0;
            int  argsCnt     = argsBase;
            bool varArgsUsed = false;


            for (int i = 0; i < method.Parameters.Length; i++)
            {
                if (isExtMethod && i == 0)
                {
                    continue;
                }

                if (method.Parameters[i].IsOut)
                {
                    continue;
                }

                Type parameterType = method.Parameters[i].Type;

                if ((parameterType == typeof(Script)) || (parameterType == typeof(ScriptExecutionContext)) || (parameterType == typeof(CallbackArguments)))
                {
                    continue;
                }

                if (i == method.Parameters.Length - 1 && method.VarArgsArrayType != null)
                {
                    int      varargCnt          = 0;
                    DynValue firstArg           = null;
                    int      scoreBeforeVargars = totalScore;

                    // update score for varargs
                    while (true)
                    {
                        var arg = args.RawGet(argsCnt, false);
                        if (arg == null)
                        {
                            break;
                        }

                        if (firstArg == null)
                        {
                            firstArg = arg;
                        }

                        argsCnt += 1;

                        varargCnt += 1;

                        int score = CalcScoreForSingleArgument(method.Parameters[i], method.VarArgsElementType, arg, isOptional: false);
                        totalScore = Math.Min(totalScore, score);
                    }

                    // check if exact-match
                    if (varargCnt == 1)
                    {
                        if (firstArg.Type == DataType.UserData && firstArg.UserData.Object != null)
                        {
                            if (Framework.Do.IsAssignableFrom(method.VarArgsArrayType, firstArg.UserData.Object.GetType()))
                            {
                                totalScore = scoreBeforeVargars;
                                continue;
                            }
                        }
                    }

                    // apply varargs penalty to score
                    if (varargCnt == 0)
                    {
                        totalScore = Math.Min(totalScore, ScriptToClrConversions.WEIGHT_VARARGS_EMPTY);
                    }

                    varArgsUsed = true;
                }
                else
                {
                    var arg = args.RawGet(argsCnt, false) ?? DynValue.Void;

                    int score = CalcScoreForSingleArgument(method.Parameters[i], parameterType, arg, method.Parameters[i].HasDefaultValue);

                    totalScore = Math.Min(totalScore, score);

                    argsCnt += 1;
                }
            }

            if (totalScore > 0)
            {
                if ((args.Count - argsBase) <= method.Parameters.Length)
                {
                    totalScore += ScriptToClrConversions.WEIGHT_NO_EXTRA_PARAMS_BONUS;
                    totalScore *= 1000;
                }
                else if (varArgsUsed)
                {
                    totalScore -= ScriptToClrConversions.WEIGHT_VARARGS_MALUS;
                    totalScore *= 1000;
                }
                else
                {
                    totalScore *= 1000;
                    totalScore -= ScriptToClrConversions.WEIGHT_EXTRA_PARAMS_MALUS * ((args.Count - argsBase) - method.Parameters.Length);
                    totalScore  = Math.Max(1, totalScore);
                }
            }

#if DEBUG_OVERLOAD_RESOLVER
            System.Diagnostics.Debug.WriteLine(string.Format("[OVERLOAD] : Score {0} for method {1}", totalScore, method.SortDiscriminant));
#endif
            return(totalScore);
        }
        /// <summary>
        /// Performs the overloaded call.
        /// </summary>
        /// <param name="script">The script.</param>
        /// <param name="obj">The object.</param>
        /// <param name="context">The context.</param>
        /// <param name="args">The arguments.</param>
        /// <returns></returns>
        /// <exception cref="ScriptRuntimeException">function call doesn't match any overload</exception>
        private DynValue PerformOverloadedCall(Script script, object obj, ScriptExecutionContext context, CallbackArguments args)
        {
            bool extMethodCacheNotExpired = IgnoreExtensionMethods || (obj == null) || m_ExtensionMethodVersion == UserData.GetExtensionMethodsChangeVersion();

            // common case, let's optimize for it
            if (m_Overloads.Count == 1 && m_ExtOverloads.Count == 0 && extMethodCacheNotExpired)
            {
                return(m_Overloads[0].Execute(script, obj, context, args));
            }

            if (m_Unsorted)
            {
                m_Overloads.Sort(new OverloadableMemberDescriptorComparer());
                m_Unsorted = false;
            }

            if (extMethodCacheNotExpired)
            {
                for (int i = 0; i < m_Cache.Length; i++)
                {
                    if (m_Cache[i] != null && CheckMatch(obj != null, args, m_Cache[i]))
                    {
#if DEBUG_OVERLOAD_RESOLVER
                        System.Diagnostics.Debug.WriteLine(string.Format("[OVERLOAD] : CACHED! slot {0}, hits: {1}", i, m_CacheHits));
#endif
                        return(m_Cache[i].Method.Execute(script, obj, context, args));
                    }
                }
            }

            // resolve on overloads first
            int maxScore = 0;
            IOverloadableMemberDescriptor bestOverload = null;

            for (int i = 0; i < m_Overloads.Count; i++)
            {
                if (obj != null || m_Overloads[i].IsStatic)
                {
                    int score = CalcScoreForOverload(context, args, m_Overloads[i], false);

                    if (score > maxScore)
                    {
                        maxScore     = score;
                        bestOverload = m_Overloads[i];
                    }
                }
            }

            if (!IgnoreExtensionMethods && (obj != null))
            {
                if (!extMethodCacheNotExpired)
                {
                    m_ExtensionMethodVersion = UserData.GetExtensionMethodsChangeVersion();
                    m_ExtOverloads           = UserData.GetExtensionMethodsByNameAndType(this.Name, this.DeclaringType);
                }

                for (int i = 0; i < m_ExtOverloads.Count; i++)
                {
                    int score = CalcScoreForOverload(context, args, m_ExtOverloads[i], true);

                    if (score > maxScore)
                    {
                        maxScore     = score;
                        bestOverload = m_ExtOverloads[i];
                    }
                }
            }


            if (bestOverload != null)
            {
                Cache(obj != null, args, bestOverload);
                return(bestOverload.Execute(script, obj, context, args));
            }

            throw new ScriptRuntimeException("function call doesn't match any overload");
        }
 /// <summary>
 /// Adds an overload.
 /// </summary>
 /// <param name="overload">The overload.</param>
 public void AddOverload(IOverloadableMemberDescriptor overload)
 {
     m_Overloads.Add(overload);
     m_Unsorted = true;
 }