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#endif19using System.Diagnostics;20using System.Runtime.CompilerServices;21 22//using Microsoft.Scripting.Generation;23 24namespace System.Management.Automation.Interpreter25{26 /// <summary>27 /// Manages creation of interpreted delegates. These delegates will get28 /// compiled if they are executed often enough.29 /// </summary>30 internal sealed class LightDelegateCreator31 {32 // null if we are forced to compile33 private readonly Interpreter _interpreter;34 private readonly Expression _lambda;35 36 // Adaptive compilation support:37 private Type _compiledDelegateType;38 private Delegate _compiled;39 private readonly object _compileLock = new object();40 41 internal LightDelegateCreator(Interpreter interpreter, LambdaExpression lambda)42 {43 Assert.NotNull(lambda);44 _interpreter = interpreter;45 _lambda = lambda;46 }47 48 // internal LightDelegateCreator(Interpreter interpreter, LightLambdaExpression lambda) {49 // Assert.NotNull(lambda);50 // _interpreter = interpreter;51 // _lambda = lambda;52 // }53 54 internal Interpreter Interpreter55 {56 get { return _interpreter; }57 }58 59 private bool HasClosure60 {61 get { return _interpreter != null && _interpreter.ClosureSize > 0; }62 }63 64 internal bool HasCompiled65 {66 get { return _compiled != null; }67 }68 69 /// <summary>70 /// True if the compiled delegate has the same type as the lambda;71 /// false if the type was changed for interpretation.72 /// </summary>73 internal bool SameDelegateType74 {75 get { return _compiledDelegateType == DelegateType; }76 }77 78 public Delegate CreateDelegate()79 {80 return CreateDelegate(null);81 }82 83 internal Delegate CreateDelegate(StrongBox<object>[] closure)84 {85 if (_compiled != null)86 {87 // If the delegate type we want is not a Func/Action, we can't88 // use the compiled code directly. So instead just fall through89 // and create an interpreted LightLambda, which will pick up90 // the compiled delegate on its first run.91 //92 // Ideally, we would just rebind the compiled delegate using93 // Delegate.CreateDelegate. Unfortunately, it doesn't work on94 // dynamic methods.95 if (SameDelegateType)96 {97 return CreateCompiledDelegate(closure);98 }99 }100 101 if (_interpreter == null)102 {103 // We can't interpret, so force a compile104 Compile(null);105 Delegate compiled = CreateCompiledDelegate(closure);106 Debug.Assert(compiled.GetType() == DelegateType);107 return compiled;108 }109 110 // Otherwise, we'll create an interpreted LightLambda111 return new LightLambda(this, closure, _interpreter._compilationThreshold).MakeDelegate(DelegateType);112 }113 114 private Type DelegateType115 {116 get117 {118 LambdaExpression le = _lambda as LambdaExpression;119 if (le != null)120 {121 return le.Type;122 }123 124 return null;125 // return ((LightLambdaExpression)_lambda).Type;126 }127 }128 129 /// <summary>130 /// Used by LightLambda to get the compiled delegate.131 /// </summary>132 internal Delegate CreateCompiledDelegate(StrongBox<object>[] closure)133 {134 Debug.Assert(HasClosure == (closure != null));135 136 if (HasClosure)137 {138 // We need to apply the closure to get the actual delegate.139 var applyClosure = (Func<StrongBox<object>[], Delegate>)_compiled;140 return applyClosure(closure);141 }142 143 return _compiled;144 }145 146 /// <summary>147 /// Create a compiled delegate for the LightLambda, and saves it so148 /// future calls to Run will execute the compiled code instead of149 /// interpreting.150 /// </summary>151 internal void Compile(object state)152 {153 if (_compiled != null)154 {155 return;156 }157 158 // Compilation is expensive, we only want to do it once.159 lock (_compileLock)160 {161 if (_compiled != null)162 {163 return;164 }165 166 // PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Interpreted lambda compiled");167 168 // Interpreter needs a standard delegate type.169 // So change the lambda's delegate type to Func<...> or170 // Action<...> so it can be called from the LightLambda.Run171 // methods.172 LambdaExpression lambda = (_lambda as LambdaExpression); // ?? (LambdaExpression)((LightLambdaExpression)_lambda).Reduce();173 if (_interpreter != null)174 {175 _compiledDelegateType = GetFuncOrAction(lambda);176 lambda = Expression.Lambda(_compiledDelegateType, lambda.Body, lambda.Name, lambda.Parameters);177 }178 179 if (HasClosure)180 {181 _compiled = LightLambdaClosureVisitor.BindLambda(lambda, _interpreter.ClosureVariables);182 }183 else184 {185 _compiled = lambda.Compile();186 }187 }188 }189 190 private static Type GetFuncOrAction(LambdaExpression lambda)191 {192 Type delegateType;193 bool isVoid = lambda.ReturnType == typeof(void);194 195 // if (isVoid && lambda.Parameters.Count == 2 &&196 // lambda.Parameters[0].IsByRef && lambda.Parameters[1].IsByRef) {197 // return typeof(ActionRef<,>).MakeGenericType(lambda.Parameters.Map(p => p.Type));198 // } else {199 Type[] types = lambda.Parameters.Map(static p => p.IsByRef ? p.Type.MakeByRefType() : p.Type);200 if (isVoid)201 {202 if (Expression.TryGetActionType(types, out delegateType))203 {204 return delegateType;205 }206 }207 else208 {209 types = types.AddLast(lambda.ReturnType);210 if (Expression.TryGetFuncType(types, out delegateType))211 {212 return delegateType;213 }214 }215 216 return lambda.Type;217 // }218 }219 }220}221 