Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
CallInstruction.cs369 linesDownload Raw Back to interpreter
1/* ****************************************************************************2 *3 * Copyright (c) Microsoft Corporation.4 *5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A6 * copy of the license can be found in the License.html file at the root of this distribution. If7 * you cannot locate the Apache License, Version 2.0, please send an email to8 * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound9 * by the terms of the Apache License, Version 2.0.10 *11 * You must not remove this notice, or any other, from this software.12 *13 *14 * ***************************************************************************/15 16using System.Collections.Generic;17using System.Reflection;18using System.Reflection.Emit;19 20namespace System.Management.Automation.Interpreter21{22    internal abstract partial class CallInstruction : Instruction23    {24        public abstract MethodInfo Info { get; }25 26        /// <summary>27        /// The number of arguments including "this" for instance methods.28        /// </summary>29        public abstract int ArgumentCount { get; }30 31        #region Construction32 33        internal CallInstruction() { }34 35        private static readonly Dictionary<MethodInfo, CallInstruction> s_cache = new Dictionary<MethodInfo, CallInstruction>();36 37        public static CallInstruction Create(MethodInfo info)38        {39            return Create(info, info.GetParameters());40        }41 42        /// <summary>43        /// Creates a new ReflectedCaller which can be used to quickly invoke the provided MethodInfo.44        /// </summary>45        public static CallInstruction Create(MethodInfo info, ParameterInfo[] parameters)46        {47            int argumentCount = parameters.Length;48            if (!info.IsStatic)49            {50                argumentCount++;51            }52 53            // A workaround for CLR bug #796414 (Unable to create delegates for Array.Get/Set):54            // T[]::Address - not supported by ETs due to T& return value55            if (info.DeclaringType != null && info.DeclaringType.IsArray && (info.Name == "Get" || info.Name == "Set"))56            {57                return GetArrayAccessor(info, argumentCount);58            }59 60            if (info is DynamicMethod || !info.IsStatic && info.DeclaringType.IsValueType)61            {62                return new MethodInfoCallInstruction(info, argumentCount);63            }64 65            if (argumentCount >= MaxHelpers)66            {67                // no delegate for this size, fallback to reflection invoke68                return new MethodInfoCallInstruction(info, argumentCount);69            }70 71            foreach (ParameterInfo pi in parameters)72            {73                if (pi.ParameterType.IsByRef)74                {75                    // we don't support ref args via generics.76                    return new MethodInfoCallInstruction(info, argumentCount);77                }78            }79 80            // see if we've created one w/ a delegate81            CallInstruction res;82            if (ShouldCache(info))83            {84                lock (s_cache)85                {86                    if (s_cache.TryGetValue(info, out res))87                    {88                        return res;89                    }90                }91            }92 93            // create it94            try95            {96                if (argumentCount < MaxArgs)97                {98                    res = FastCreate(info, parameters);99                }100                else101                {102                    res = SlowCreate(info, parameters);103                }104            }105            catch (TargetInvocationException tie)106            {107                if (tie.InnerException is not NotSupportedException)108                {109                    throw;110                }111 112                res = new MethodInfoCallInstruction(info, argumentCount);113            }114            catch (NotSupportedException)115            {116                // if Delegate.CreateDelegate can't handle the method fallback to117                // the slow reflection version.  For example this can happen w/118                // a generic method defined on an interface and implemented on a class or119                // a virtual generic method.120                res = new MethodInfoCallInstruction(info, argumentCount);121            }122 123            // cache it for future users if it's a reasonable method to cache124            if (ShouldCache(info))125            {126                lock (s_cache)127                {128                    s_cache[info] = res;129                }130            }131 132            return res;133        }134 135        private static CallInstruction GetArrayAccessor(MethodInfo info, int argumentCount)136        {137            Type arrayType = info.DeclaringType;138            bool isGetter = info.Name == "Get";139            switch (arrayType.GetArrayRank())140            {141                case 1:142                    return Create(isGetter ?143                        arrayType.GetMethod("GetValue", new[] { typeof(int) }) :144                        new Action<Array, int, object>(ArrayItemSetter1).GetMethodInfo()145                    );146 147                case 2:148                    return Create(isGetter ?149                        arrayType.GetMethod("GetValue", new[] { typeof(int), typeof(int) }) :150                        new Action<Array, int, int, object>(ArrayItemSetter2).GetMethodInfo()151                    );152 153                case 3:154                    return Create(isGetter ?155                        arrayType.GetMethod("GetValue", new[] { typeof(int), typeof(int), typeof(int) }) :156                        new Action<Array, int, int, int, object>(ArrayItemSetter3).GetMethodInfo()157                    );158 159                default:160                    return new MethodInfoCallInstruction(info, argumentCount);161            }162        }163 164        public static void ArrayItemSetter1(Array array, int index0, object value)165        {166            array.SetValue(value, index0);167        }168 169        public static void ArrayItemSetter2(Array array, int index0, int index1, object value)170        {171            array.SetValue(value, index0, index1);172        }173 174        public static void ArrayItemSetter3(Array array, int index0, int index1, int index2, object value)175        {176            array.SetValue(value, index0, index1, index2);177        }178 179        private static bool ShouldCache(MethodInfo info)180        {181            return info is not DynamicMethod;182        }183 184        /// <summary>185        /// Gets the next type or null if no more types are available.186        /// </summary>187        private static Type TryGetParameterOrReturnType(MethodInfo target, ParameterInfo[] pi, int index)188        {189            if (!target.IsStatic)190            {191                index--;192                if (index < 0)193                {194                    return target.DeclaringType;195                }196            }197 198            if (index < pi.Length)199            {200                // next in signature201                return pi[index].ParameterType;202            }203 204            if (target.ReturnType == typeof(void) || index > pi.Length)205            {206                // no more parameters207                return null;208            }209 210            // last parameter on Invoke is return type211            return target.ReturnType;212        }213 214        private static bool IndexIsNotReturnType(int index, MethodInfo target, ParameterInfo[] pi)215        {216            return pi.Length != index || !target.IsStatic;217        }218 219        /// <summary>220        /// Uses reflection to create new instance of the appropriate ReflectedCaller.221        /// </summary>222        private static CallInstruction SlowCreate(MethodInfo info, ParameterInfo[] pis)223        {224            List<Type> types = new List<Type>();225            if (!info.IsStatic)226            {227                types.Add(info.DeclaringType);228            }229 230            foreach (ParameterInfo pi in pis)231            {232                types.Add(pi.ParameterType);233            }234 235            if (info.ReturnType != typeof(void))236            {237                types.Add(info.ReturnType);238            }239 240            Type[] arrTypes = types.ToArray();241 242            return (CallInstruction)Activator.CreateInstance(GetHelperType(info, arrTypes), info);243        }244 245        #endregion246 247        #region Instruction248 249        public sealed override int ProducedStack { get { return Info.ReturnType == typeof(void) ? 0 : 1; } }250 251        public sealed override int ConsumedStack { get { return ArgumentCount; } }252 253        public sealed override string InstructionName254        {255            get { return "Call"; }256        }257 258        public override string ToString()259        {260            return "Call(" + Info + ")";261        }262 263        #endregion264    }265 266    internal sealed partial class MethodInfoCallInstruction : CallInstruction267    {268        private readonly MethodInfo _target;269        private readonly int _argumentCount;270 271        public override MethodInfo Info { get { return _target; } }272 273        public override int ArgumentCount { get { return _argumentCount; } }274 275        internal MethodInfoCallInstruction(MethodInfo target, int argumentCount)276        {277            _target = target;278            _argumentCount = argumentCount;279        }280 281        public override object Invoke(params object[] args)282        {283            return InvokeWorker(args);284        }285 286        public override object InvokeInstance(object instance, params object[] args)287        {288            if (_target.IsStatic)289            {290                try291                {292                    return _target.Invoke(null, args);293                }294                catch (TargetInvocationException e)295                {296                    throw ExceptionHelpers.UpdateForRethrow(e.InnerException);297                }298            }299 300            try301            {302                return _target.Invoke(instance, args);303            }304            catch (TargetInvocationException e)305            {306                throw ExceptionHelpers.UpdateForRethrow(e.InnerException);307            }308        }309 310        private object InvokeWorker(params object[] args)311        {312            if (_target.IsStatic)313            {314                try315                {316                    return _target.Invoke(null, args);317                }318                catch (TargetInvocationException e)319                {320                    throw ExceptionHelpers.UpdateForRethrow(e.InnerException);321                }322            }323 324            try325            {326                return _target.Invoke(args[0], GetNonStaticArgs(args));327            }328            catch (TargetInvocationException e)329            {330                throw ExceptionHelpers.UpdateForRethrow(e.InnerException);331            }332        }333 334        private static object[] GetNonStaticArgs(object[] args)335        {336            object[] newArgs = new object[args.Length - 1];337            for (int i = 0; i < newArgs.Length; i++)338            {339                newArgs[i] = args[i + 1];340            }341 342            return newArgs;343        }344 345        public sealed override int Run(InterpretedFrame frame)346        {347            int first = frame.StackIndex - _argumentCount;348            object[] args = new object[_argumentCount];349            for (int i = 0; i < args.Length; i++)350            {351                args[i] = frame.Data[first + i];352            }353 354            object ret = Invoke(args);355            if (_target.ReturnType != typeof(void))356            {357                frame.Data[first] = ret;358                frame.StackIndex = first + 1;359            }360            else361            {362                frame.StackIndex = first;363            }364 365            return 1;366        }367    }368}369