MegaBites-AI/Windows-powershell
0372
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 