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 * dlr@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 16#if !CLR217using System.Linq.Expressions;18#else19using Microsoft.Scripting.Ast;20#endif21using System.Reflection;22using System.Reflection.Emit;23using System.Runtime.CompilerServices;24using System.Security;25using System.Threading;26 27//using Microsoft.Scripting.Generation;28 29using AstUtils = System.Management.Automation.Interpreter.Utils;30 31namespace System.Management.Automation.Interpreter32{33 internal sealed class LightLambdaCompileEventArgs : EventArgs34 {35 public Delegate Compiled { get; }36 37 internal LightLambdaCompileEventArgs(Delegate compiled)38 {39 Compiled = compiled;40 }41 }42 43 internal partial class LightLambda44 {45 private readonly StrongBox<object>[] _closure;46 private readonly Interpreter _interpreter;47 private static readonly CacheDict<Type, Func<LightLambda, Delegate>> s_runCache = new CacheDict<Type, Func<LightLambda, Delegate>>(100);48 49 // Adaptive compilation support50 private readonly LightDelegateCreator _delegateCreator;51 private Delegate _compiled;52 private int _compilationThreshold;53 54 /// <summary>55 /// Provides notification that the LightLambda has been compiled.56 /// </summary>57 public event EventHandler<LightLambdaCompileEventArgs> Compile;58 59 internal LightLambda(LightDelegateCreator delegateCreator, StrongBox<object>[] closure, int compilationThreshold)60 {61 _delegateCreator = delegateCreator;62 _closure = closure;63 _interpreter = delegateCreator.Interpreter;64 _compilationThreshold = compilationThreshold;65 }66 67 private static Func<LightLambda, Delegate> GetRunDelegateCtor(Type delegateType)68 {69 lock (s_runCache)70 {71 Func<LightLambda, Delegate> fastCtor;72 if (s_runCache.TryGetValue(delegateType, out fastCtor))73 {74 return fastCtor;75 }76 77 return MakeRunDelegateCtor(delegateType);78 }79 }80 81 private static Func<LightLambda, Delegate> MakeRunDelegateCtor(Type delegateType)82 {83 var method = delegateType.GetMethod("Invoke");84 var paramInfos = method.GetParameters();85 Type[] paramTypes;86 string name = "Run";87 88 if (paramInfos.Length >= MaxParameters)89 {90 return null;91 }92 93 if (method.ReturnType == typeof(void))94 {95 name += "Void";96 paramTypes = new Type[paramInfos.Length];97 }98 else99 {100 paramTypes = new Type[paramInfos.Length + 1];101 paramTypes[paramTypes.Length - 1] = method.ReturnType;102 }103 104 MethodInfo runMethod;105 106 if (method.ReturnType == typeof(void) && paramTypes.Length == 2 &&107 paramInfos[0].ParameterType.IsByRef && paramInfos[1].ParameterType.IsByRef)108 {109 runMethod = typeof(LightLambda).GetMethod("RunVoidRef2", BindingFlags.NonPublic | BindingFlags.Instance);110 paramTypes[0] = paramInfos[0].ParameterType.GetElementType();111 paramTypes[1] = paramInfos[1].ParameterType.GetElementType();112 }113 else if (method.ReturnType == typeof(void) && paramTypes.Length == 0)114 {115 runMethod = typeof(LightLambda).GetMethod("RunVoid0", BindingFlags.NonPublic | BindingFlags.Instance);116 }117 else118 {119 for (int i = 0; i < paramInfos.Length; i++)120 {121 paramTypes[i] = paramInfos[i].ParameterType;122 if (paramTypes[i].IsByRef)123 {124 return null;125 }126 }127 128 if (DelegateHelpers.MakeDelegate(paramTypes) == delegateType)129 {130 name = "Make" + name + paramInfos.Length;131 132 MethodInfo ctorMethod = typeof(LightLambda).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(paramTypes);133 return s_runCache[delegateType] = (Func<LightLambda, Delegate>)ctorMethod.CreateDelegate(typeof(Func<LightLambda, Delegate>));134 }135 136 runMethod = typeof(LightLambda).GetMethod(name + paramInfos.Length, BindingFlags.NonPublic | BindingFlags.Instance);137 }138 139#if !SILVERLIGHT140 try141 {142 DynamicMethod dm = new DynamicMethod("FastCtor", typeof(Delegate), new[] { typeof(LightLambda) }, typeof(LightLambda), true);143 var ilgen = dm.GetILGenerator();144 ilgen.Emit(OpCodes.Ldarg_0);145 ilgen.Emit(OpCodes.Ldftn, runMethod.IsGenericMethodDefinition ? runMethod.MakeGenericMethod(paramTypes) : runMethod);146 ilgen.Emit(OpCodes.Newobj, delegateType.GetConstructor(new[] { typeof(object), typeof(IntPtr) }));147 ilgen.Emit(OpCodes.Ret);148 return s_runCache[delegateType] = (Func<LightLambda, Delegate>)dm.CreateDelegate(typeof(Func<LightLambda, Delegate>));149 }150 catch (SecurityException)151 {152 }153#endif154 155 // we don't have permission for restricted skip visibility dynamic methods, use the slower Delegate.CreateDelegate.156 var targetMethod = runMethod.IsGenericMethodDefinition ? runMethod.MakeGenericMethod(paramTypes) : runMethod;157 return s_runCache[delegateType] = lambda => targetMethod.CreateDelegate(delegateType, lambda);158 }159 160 // TODO enable sharing of these custom delegates161 private Delegate CreateCustomDelegate(Type delegateType)162 {163 // PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Synchronously compiling a custom delegate");164 165 var method = delegateType.GetMethod("Invoke");166 var paramInfos = method.GetParameters();167 var parameters = new ParameterExpression[paramInfos.Length];168 var parametersAsObject = new Expression[paramInfos.Length];169 for (int i = 0; i < paramInfos.Length; i++)170 {171 ParameterExpression parameter = Expression.Parameter(paramInfos[i].ParameterType, paramInfos[i].Name);172 parameters[i] = parameter;173 parametersAsObject[i] = Expression.Convert(parameter, typeof(object));174 }175 176 var data = Expression.NewArrayInit(typeof(object), parametersAsObject);177 var self = AstUtils.Constant(this);178 var runMethod = typeof(LightLambda).GetMethod("Run");179 var body = Expression.Convert(Expression.Call(self, runMethod, data), method.ReturnType);180 var lambda = Expression.Lambda(delegateType, body, parameters);181 return lambda.Compile();182 }183 184 internal Delegate MakeDelegate(Type delegateType)185 {186 Func<LightLambda, Delegate> fastCtor = GetRunDelegateCtor(delegateType);187 if (fastCtor != null)188 {189 return fastCtor(this);190 }191 else192 {193 return CreateCustomDelegate(delegateType);194 }195 }196 197 private bool TryGetCompiled()198 {199 // Use the compiled delegate if available.200 if (_delegateCreator.HasCompiled)201 {202 _compiled = _delegateCreator.CreateCompiledDelegate(_closure);203 204 // Send it to anyone who's interested.205 var compileEvent = Compile;206 if (compileEvent != null && _delegateCreator.SameDelegateType)207 {208 compileEvent(this, new LightLambdaCompileEventArgs(_compiled));209 }210 211 return true;212 }213 214 // Don't lock here, it's a frequently hit path.215 //216 // There could be multiple threads racing, but that is okay.217 // Two bad things can happen:218 // * We miss decrements (some thread sets the counter forward)219 // * We might enter the "if" branch more than once.220 //221 // The first is okay, it just means we take longer to compile.222 // The second we explicitly guard against inside of Compile().223 //224 // We can't miss 0. The first thread that writes -1 must have read 0 and hence start compilation.225 if (unchecked(_compilationThreshold--) == 0)226 {227#if SILVERLIGHT228 if (PlatformAdaptationLayer.IsCompactFramework) {229 _compilationThreshold = Int32.MaxValue;230 return false;231 }232#endif233 if (_interpreter.CompileSynchronously)234 {235 _delegateCreator.Compile(null);236 return TryGetCompiled();237 }238 else239 {240 // Kick off the compile on another thread so this one can keep going241 ThreadPool.QueueUserWorkItem(_delegateCreator.Compile, null);242 }243 }244 245 return false;246 }247 248 private InterpretedFrame MakeFrame()249 {250 return new InterpretedFrame(_interpreter, _closure);251 }252 253 internal void RunVoidRef2<T0, T1>(ref T0 arg0, ref T1 arg1)254 {255 // if (_compiled != null || TryGetCompiled()) {256 // ((ActionRef<T0, T1>)_compiled)(ref arg0, ref arg1);257 // return;258 // }259 260 // copy in and copy out for today...261 var frame = MakeFrame();262 frame.Data[0] = arg0;263 frame.Data[1] = arg1;264 var currentFrame = frame.Enter();265 try266 {267 _interpreter.Run(frame);268 }269 finally270 {271 frame.Leave(currentFrame);272 arg0 = (T0)frame.Data[0];273 arg1 = (T1)frame.Data[1];274 }275 }276 277 public object Run(params object[] arguments)278 {279 if (_compiled != null || TryGetCompiled())280 {281 return _compiled.DynamicInvoke(arguments);282 }283 284 var frame = MakeFrame();285 for (int i = 0; i < arguments.Length; i++)286 {287 frame.Data[i] = arguments[i];288 }289 290 var currentFrame = frame.Enter();291 try292 {293 _interpreter.Run(frame);294 }295 finally296 {297 frame.Leave(currentFrame);298 }299 300 return frame.Pop();301 }302 }303}304 