1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Linq.Expressions;
18 using Microsoft.Scripting.Ast;
20 using Microsoft.Scripting.Ast;
24 using System.Collections.Generic;
25 using System.Diagnostics;
26 using System.Runtime.CompilerServices;
27 using System.Threading;
28 using Microsoft.Scripting.Generation;
29 using Microsoft.Scripting.Utils;
31 namespace Microsoft.Scripting.Interpreter {
34 /// Manages creation of interpreted delegates. These delegates will get
35 /// compiled if they are executed often enough.
37 internal sealed class LightDelegateCreator {
38 // null if we are forced to compile
39 private readonly Interpreter _interpreter;
40 private readonly Expression _lambda;
42 // Adaptive compilation support:
43 private Type _compiledDelegateType;
44 private Delegate _compiled;
45 private readonly object _compileLock = new object();
47 internal LightDelegateCreator(Interpreter interpreter, LambdaExpression lambda) {
48 Assert.NotNull(lambda);
49 _interpreter = interpreter;
53 internal LightDelegateCreator(Interpreter interpreter, LightLambdaExpression lambda) {
54 Assert.NotNull(lambda);
55 _interpreter = interpreter;
59 internal Interpreter Interpreter {
60 get { return _interpreter; }
63 private bool HasClosure {
64 get { return _interpreter != null && _interpreter.ClosureSize > 0; }
67 internal bool HasCompiled {
68 get { return _compiled != null; }
72 /// true if the compiled delegate has the same type as the lambda;
73 /// false if the type was changed for interpretation.
75 internal bool SameDelegateType {
76 get { return _compiledDelegateType == DelegateType; }
79 internal Delegate CreateDelegate() {
80 return CreateDelegate(null);
83 internal Delegate CreateDelegate(StrongBox<object>[] closure) {
84 if (_compiled != null) {
85 // If the delegate type we want is not a Func/Action, we can't
86 // use the compiled code directly. So instead just fall through
87 // and create an interpreted LightLambda, which will pick up
88 // the compiled delegate on its first run.
90 // Ideally, we would just rebind the compiled delegate using
91 // Delegate.CreateDelegate. Unfortunately, it doesn't work on
93 if (SameDelegateType) {
94 return CreateCompiledDelegate(closure);
98 if (_interpreter == null) {
99 // We can't interpret, so force a compile
101 Delegate compiled = CreateCompiledDelegate(closure);
102 Debug.Assert(compiled.GetType() == DelegateType);
106 // Otherwise, we'll create an interpreted LightLambda
107 return new LightLambda(this, closure, _interpreter._compilationThreshold).MakeDelegate(DelegateType);
110 private Type DelegateType {
112 LambdaExpression le = _lambda as LambdaExpression;
117 return ((LightLambdaExpression)_lambda).Type;
122 /// Used by LightLambda to get the compiled delegate.
124 internal Delegate CreateCompiledDelegate(StrongBox<object>[] closure) {
125 Debug.Assert(HasClosure == (closure != null));
128 // We need to apply the closure to get the actual delegate.
129 var applyClosure = (Func<StrongBox<object>[], Delegate>)_compiled;
130 return applyClosure(closure);
136 /// Create a compiled delegate for the LightLambda, and saves it so
137 /// future calls to Run will execute the compiled code instead of
140 internal void Compile(object state) {
141 if (_compiled != null) {
145 // Compilation is expensive, we only want to do it once.
146 lock (_compileLock) {
147 if (_compiled != null) {
151 PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Interpreted lambda compiled");
153 // Interpreter needs a standard delegate type.
154 // So change the lambda's delegate type to Func<...> or
155 // Action<...> so it can be called from the LightLambda.Run
157 LambdaExpression lambda = (_lambda as LambdaExpression) ?? (LambdaExpression)((LightLambdaExpression)_lambda).Reduce();
158 if (_interpreter != null) {
159 _compiledDelegateType = GetFuncOrAction(lambda);
160 lambda = Expression.Lambda(_compiledDelegateType, lambda.Body, lambda.Name, lambda.Parameters);
164 _compiled = LightLambdaClosureVisitor.BindLambda(lambda, _interpreter.ClosureVariables);
166 _compiled = lambda.Compile();
171 private static Type GetFuncOrAction(LambdaExpression lambda) {
173 bool isVoid = lambda.ReturnType == typeof(void);
175 if (isVoid && lambda.Parameters.Count == 2 &&
176 lambda.Parameters[0].IsByRef && lambda.Parameters[1].IsByRef) {
177 return typeof(ActionRef<,>).MakeGenericType(lambda.Parameters.Map(p => p.Type));
179 Type[] types = lambda.Parameters.Map(p => p.IsByRef ? p.Type.MakeByRefType() : p.Type);
181 if (Expression.TryGetActionType(types, out delegateType)) {
185 types = types.AddLast(lambda.ReturnType);
186 if (Expression.TryGetFuncType(types, out delegateType)) {