Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Interpreter / LightDelegateCreator.cs
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. 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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 #if FEATURE_CORE_DLR
17 using System.Linq.Expressions;
18 using Microsoft.Scripting.Ast;
19 #else
20 using Microsoft.Scripting.Ast;
21 #endif
22
23 using System;
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;
30
31 namespace Microsoft.Scripting.Interpreter {
32     
33     /// <summary>
34     /// Manages creation of interpreted delegates. These delegates will get
35     /// compiled if they are executed often enough.
36     /// </summary>
37     internal sealed class LightDelegateCreator {
38         // null if we are forced to compile
39         private readonly Interpreter _interpreter;
40         private readonly Expression _lambda;
41
42         // Adaptive compilation support:
43         private Type _compiledDelegateType;
44         private Delegate _compiled;
45         private readonly object _compileLock = new object();
46
47         internal LightDelegateCreator(Interpreter interpreter, LambdaExpression lambda) {
48             Assert.NotNull(lambda);
49             _interpreter = interpreter;
50             _lambda = lambda;
51         }
52
53         internal LightDelegateCreator(Interpreter interpreter, LightLambdaExpression lambda) {
54             Assert.NotNull(lambda);
55             _interpreter = interpreter;
56             _lambda = lambda;
57         }
58
59         internal Interpreter Interpreter {
60             get { return _interpreter; }
61         }
62
63         private bool HasClosure {
64             get { return _interpreter != null && _interpreter.ClosureSize > 0; }
65         }
66
67         internal bool HasCompiled {
68             get { return _compiled != null; }
69         }
70
71         /// <summary>
72         /// true if the compiled delegate has the same type as the lambda;
73         /// false if the type was changed for interpretation.
74         /// </summary>
75         internal bool SameDelegateType {
76             get { return _compiledDelegateType == DelegateType; }
77         }
78
79         internal Delegate CreateDelegate() {
80             return CreateDelegate(null);
81         }
82
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.
89                 //
90                 // Ideally, we would just rebind the compiled delegate using
91                 // Delegate.CreateDelegate. Unfortunately, it doesn't work on
92                 // dynamic methods.
93                 if (SameDelegateType) {
94                     return CreateCompiledDelegate(closure);
95                 }
96             }
97
98             if (_interpreter == null) {
99                 // We can't interpret, so force a compile
100                 Compile(null);
101                 Delegate compiled = CreateCompiledDelegate(closure);
102                 Debug.Assert(compiled.GetType() == DelegateType);
103                 return compiled;
104             }
105
106             // Otherwise, we'll create an interpreted LightLambda
107             return new LightLambda(this, closure, _interpreter._compilationThreshold).MakeDelegate(DelegateType);
108         }
109
110         private Type DelegateType {
111             get {
112                 LambdaExpression le = _lambda as LambdaExpression;
113                 if (le != null) {
114                     return le.Type;
115                 }
116
117                 return ((LightLambdaExpression)_lambda).Type;
118             }
119         }
120
121         /// <summary>
122         /// Used by LightLambda to get the compiled delegate.
123         /// </summary>
124         internal Delegate CreateCompiledDelegate(StrongBox<object>[] closure) {
125             Debug.Assert(HasClosure == (closure != null));
126
127             if (HasClosure) {
128                 // We need to apply the closure to get the actual delegate.
129                 var applyClosure = (Func<StrongBox<object>[], Delegate>)_compiled;
130                 return applyClosure(closure);
131             }
132             return _compiled;
133         }
134
135         /// <summary>
136         /// Create a compiled delegate for the LightLambda, and saves it so
137         /// future calls to Run will execute the compiled code instead of
138         /// interpreting.
139         /// </summary>
140         internal void Compile(object state) {
141             if (_compiled != null) {
142                 return;
143             }
144
145             // Compilation is expensive, we only want to do it once.
146             lock (_compileLock) {
147                 if (_compiled != null) {
148                     return;
149                 }
150
151                 PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Interpreted lambda compiled");
152                 
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
156                 // methods.
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);
161                 }
162
163                 if (HasClosure) {
164                     _compiled = LightLambdaClosureVisitor.BindLambda(lambda, _interpreter.ClosureVariables);
165                 } else {
166                     _compiled = lambda.Compile();
167                 }
168             }
169         }
170
171         private static Type GetFuncOrAction(LambdaExpression lambda) {
172             Type delegateType;
173             bool isVoid = lambda.ReturnType == typeof(void);
174
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));
178             } else {
179                 Type[] types = lambda.Parameters.Map(p => p.IsByRef ? p.Type.MakeByRefType() : p.Type);
180                 if (isVoid) {
181                     if (Expression.TryGetActionType(types, out delegateType)) {
182                         return delegateType;
183                     }
184                 } else {
185                     types = types.AddLast(lambda.ReturnType);
186                     if (Expression.TryGetFuncType(types, out delegateType)) {
187                         return delegateType;
188                     }
189                 }
190                 return lambda.Type;
191             }
192         }
193     }
194 }