Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Interpreter / Instructions / TypeOperations.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 using System;
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Reflection;
20 using System.Runtime.CompilerServices;
21 using Microsoft.Scripting.Runtime;
22 using Microsoft.Scripting.Utils;
23 using System.Linq;
24
25 namespace Microsoft.Scripting.Interpreter {
26     internal sealed class CreateDelegateInstruction : Instruction {
27         private readonly LightDelegateCreator _creator;
28
29         internal CreateDelegateInstruction(LightDelegateCreator delegateCreator) {
30             _creator = delegateCreator;
31         }
32
33         public override int ConsumedStack { get { return _creator.Interpreter.ClosureSize; } }
34         public override int ProducedStack { get { return 1; } }
35
36         public override int Run(InterpretedFrame frame) {
37             StrongBox<object>[] closure;
38             if (ConsumedStack > 0) {
39                 closure = new StrongBox<object>[ConsumedStack];
40                 for (int i = closure.Length - 1; i >= 0; i--) {
41                     closure[i] = (StrongBox<object>)frame.Pop();
42                 }
43             } else {
44                 closure = null;
45             }
46
47             Delegate d = _creator.CreateDelegate(closure);
48
49             frame.Push(d);
50             return +1;
51         }
52     }
53
54     internal sealed class NewInstruction : Instruction {
55         private readonly ConstructorInfo _constructor;
56         private readonly int _argCount;
57
58         public NewInstruction(ConstructorInfo constructor) {
59             _constructor = constructor;
60             _argCount = constructor.GetParameters().Length;
61
62         }
63         public override int ConsumedStack { get { return _argCount; } }
64         public override int ProducedStack { get { return 1; } }
65
66         public override int Run(InterpretedFrame frame) {
67             object[] args = new object[_argCount];
68             for (int i = _argCount - 1; i >= 0; i--) {
69                 args[i] = frame.Pop();
70             }
71
72             object ret;
73             try {
74                 ret = _constructor.Invoke(args);
75             } catch (TargetInvocationException e) {
76                 ExceptionHelpers.UpdateForRethrow(e.InnerException);
77                 throw e.InnerException;
78             }
79
80             frame.Push(ret);
81             return +1;
82         }
83
84         public override string ToString() {
85             return "New " + _constructor.DeclaringType.Name + "(" + _constructor + ")";
86         }
87     }
88
89     internal sealed class DefaultValueInstruction<T> : Instruction {
90         internal DefaultValueInstruction() { }
91
92         public override int ConsumedStack { get { return 0; } }
93         public override int ProducedStack { get { return 1; } }
94
95         public override int Run(InterpretedFrame frame) {
96             frame.Push(default(T));
97             return +1;
98         }
99
100         public override string ToString() {
101             return "New " + typeof(T);
102         }
103     }
104
105     internal sealed class TypeIsInstruction<T> : Instruction {
106         internal TypeIsInstruction() { }
107
108         public override int ConsumedStack { get { return 1; } }
109         public override int ProducedStack { get { return 1; } }
110
111         public override int Run(InterpretedFrame frame) {
112             // unfortunately Type.IsInstanceOfType() is 35-times slower than "is T" so we use generic code:
113             frame.Push(ScriptingRuntimeHelpers.BooleanToObject(frame.Pop() is T));
114             return +1;
115         }
116
117         public override string ToString() {
118             return "TypeIs " + typeof(T).Name; 
119         }
120     }
121
122     internal sealed class TypeAsInstruction<T> : Instruction {
123         internal TypeAsInstruction() { }
124
125         public override int ConsumedStack { get { return 1; } }
126         public override int ProducedStack { get { return 1; } }
127
128         public override int Run(InterpretedFrame frame) {
129             // can't use as w/o generic constraint
130             object value = frame.Pop();
131             if (value is T) {
132                 frame.Push(value);
133             } else {
134                 frame.Push(null);
135             }
136             return +1;
137         }
138
139         public override string ToString() {
140             return "TypeAs " + typeof(T).Name;
141         }
142     }
143
144     internal sealed class TypeEqualsInstruction : Instruction {
145         public static readonly TypeEqualsInstruction Instance = new TypeEqualsInstruction();
146
147         public override int ConsumedStack { get { return 2; } }
148         public override int ProducedStack { get { return 1; } }
149
150         private TypeEqualsInstruction() {
151         }
152
153         public override int Run(InterpretedFrame frame) {
154             object type = frame.Pop();
155             object obj = frame.Pop();
156             frame.Push(ScriptingRuntimeHelpers.BooleanToObject(obj != null && (object)obj.GetType() == type));
157             return +1;
158         }
159
160         public override string InstructionName {
161             get { return "TypeEquals()"; }
162         }
163     }
164
165     internal sealed class WrapToNullableInstruction<T> : Instruction {
166
167         readonly Type elementType;
168         ConstructorInfo ctor;
169
170         public override int ConsumedStack { get { return 1; } }
171         public override int ProducedStack { get { return 1; } }
172
173         internal WrapToNullableInstruction(Type elementType) {
174             this.elementType = elementType;
175         }
176
177         public override int Run(InterpretedFrame frame) {
178             var r = frame.Data[frame.StackIndex - 1];
179
180             // Don't need to wrap null values
181             if (r == null)
182                 return 1;
183
184             ctor = typeof (Nullable<>).MakeGenericType (elementType).GetDeclaredConstructors ().First ();
185             frame.Data[frame.StackIndex - 1] = ctor.Invoke (new [] { r });
186             return 1;
187         }
188
189         public override string InstructionName {
190             get { return "WrapTo " + typeof(T) + "?"; }
191         }
192     }
193 }