Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Interpreter / Instructions / InstructionList.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 // Enables instruction counting and displaying stats at process exit.
16 // #define STATS
17
18 using System;
19 using System.Collections.Generic;
20 using System.Diagnostics;
21 using System.Reflection;
22 using System.Runtime.CompilerServices;
23 using System.Security;
24 using Microsoft.Scripting.Runtime;
25 using Microsoft.Scripting.Utils;
26
27 namespace Microsoft.Scripting.Interpreter {
28     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
29     [DebuggerTypeProxy(typeof(InstructionArray.DebugView))]
30     public struct InstructionArray {
31         internal readonly int MaxStackDepth;
32         internal readonly int MaxContinuationDepth;
33         internal readonly Instruction[] Instructions;
34         internal readonly object[] Objects;
35         internal readonly RuntimeLabel[] Labels;
36
37         // list of (instruction index, cookie) sorted by instruction index:
38         internal readonly List<KeyValuePair<int, object>> DebugCookies;
39
40         internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions, 
41             object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies) {
42
43             MaxStackDepth = maxStackDepth;
44             MaxContinuationDepth = maxContinuationDepth;
45             Instructions = instructions;
46             DebugCookies = debugCookies;
47             Objects = objects;
48             Labels = labels;
49         }
50
51         internal int Length {
52             get { return Instructions.Length; }
53         }
54
55         #region Debug View
56
57         internal sealed class DebugView {
58             private readonly InstructionArray _array;
59
60             public DebugView(InstructionArray array) {
61                 _array = array;
62
63             }
64
65             [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
66             public InstructionList.DebugView.InstructionView[]/*!*/ A0 {
67                 get {
68                     return InstructionList.DebugView.GetInstructionViews(
69                         _array.Instructions, 
70                         _array.Objects, 
71                         (index) => _array.Labels[index].Index, 
72                         _array.DebugCookies
73                     );
74                 }
75             }
76         }
77
78         #endregion
79     }
80
81     [DebuggerTypeProxy(typeof(InstructionList.DebugView))]
82     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
83     public sealed class InstructionList {
84         private readonly List<Instruction> _instructions = new List<Instruction>();
85         private List<object> _objects;
86
87         private int _currentStackDepth;
88         private int _maxStackDepth;
89         private int _currentContinuationsDepth;
90         private int _maxContinuationDepth;
91         private int _runtimeLabelCount;
92         private List<BranchLabel> _labels;
93         
94         // list of (instruction index, cookie) sorted by instruction index:
95         private List<KeyValuePair<int, object>> _debugCookies = null;
96
97         #region Debug View
98
99         internal sealed class DebugView {
100             private readonly InstructionList _list;
101
102             public DebugView(InstructionList list) {
103                 _list = list;
104             }
105
106             [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
107             public InstructionView[]/*!*/ A0 {
108                 get {
109                     return GetInstructionViews(
110                         _list._instructions, 
111                         _list._objects, 
112                         (index) => _list._labels[index].TargetIndex, 
113                         _list._debugCookies
114                     );
115                 }
116             }
117
118             internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects,
119                 Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies) {
120
121                 var result = new List<InstructionView>();
122                 int index = 0;
123                 int stackDepth = 0;
124                 int continuationsDepth = 0;
125
126                 var cookieEnumerator = (debugCookies != null ? debugCookies : new KeyValuePair<int, object>[0]).GetEnumerator();
127                 var hasCookie = cookieEnumerator.MoveNext();
128
129                 for (int i = 0; i < instructions.Count; i++) {
130                     object cookie = null;
131                     while (hasCookie && cookieEnumerator.Current.Key == i) {
132                         cookie = cookieEnumerator.Current.Value;
133                         hasCookie = cookieEnumerator.MoveNext();
134                     }
135
136                     int stackDiff = instructions[i].StackBalance;
137                     int contDiff = instructions[i].ContinuationsBalance;
138                     string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects);
139                     result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth));
140                     
141                     index++;
142                     stackDepth += stackDiff;
143                     continuationsDepth += contDiff;
144                 }
145                 return result.ToArray();
146             }
147
148             [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")]
149             internal struct InstructionView {
150                 private readonly int _index;
151                 private readonly int _stackDepth;
152                 private readonly int _continuationsDepth;
153                 private readonly string _name;
154                 private readonly Instruction _instruction;
155
156                 internal string GetName() {
157                     return _index.ToString() +
158                         (_continuationsDepth == 0 ? "" : " C(" + _continuationsDepth.ToString() + ")") +
159                         (_stackDepth == 0 ? "" : " S(" + _stackDepth.ToString() + ")");
160                 }
161
162                 internal string GetValue() {
163                     return _name;
164                 }
165
166                 internal string GetDisplayType() {
167                     return _instruction.ContinuationsBalance.ToString() + "/" + _instruction.StackBalance.ToString();
168                 }
169
170                 public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth) {
171                     _instruction = instruction;
172                     _name = name;
173                     _index = index;
174                     _stackDepth = stackDepth;
175                     _continuationsDepth = continuationsDepth;
176                 }
177             }
178         }
179                         
180         #endregion
181
182         #region Core Emit Ops
183
184         public void Emit(Instruction instruction) {
185             _instructions.Add(instruction);
186             UpdateStackDepth(instruction);
187         }
188
189         private void UpdateStackDepth(Instruction instruction) {
190             Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 &&
191                 instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0);
192
193             _currentStackDepth -= instruction.ConsumedStack;
194             Debug.Assert(_currentStackDepth >= 0);
195             _currentStackDepth += instruction.ProducedStack;
196             if (_currentStackDepth > _maxStackDepth) {
197                 _maxStackDepth = _currentStackDepth;
198             }
199
200             _currentContinuationsDepth -= instruction.ConsumedContinuations;
201             Debug.Assert(_currentContinuationsDepth >= 0);
202             _currentContinuationsDepth += instruction.ProducedContinuations;
203             if (_currentContinuationsDepth > _maxContinuationDepth) {
204                 _maxContinuationDepth = _currentContinuationsDepth;
205             }
206         }
207
208         /// <summary>
209         /// Attaches a cookie to the last emitted instruction.
210         /// </summary>
211         [Conditional("DEBUG")]
212         public void SetDebugCookie(object cookie) {
213 #if DEBUG
214             if (_debugCookies == null) {
215                 _debugCookies = new List<KeyValuePair<int, object>>();
216             }
217
218             Debug.Assert(Count > 0);
219             _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie));
220 #endif
221         }
222
223         public int Count {
224             get { return _instructions.Count; }
225         }
226
227         public int CurrentStackDepth {
228             get { return _currentStackDepth; }
229         }
230
231         public int CurrentContinuationsDepth {
232             get { return _currentContinuationsDepth; }
233         }
234
235         public int MaxStackDepth {
236             get { return _maxStackDepth; }
237         }
238
239         internal Instruction GetInstruction(int index) {
240             return _instructions[index];
241         }
242
243 #if STATS
244         private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>();
245         private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>();
246
247         static InstructionList() {
248             AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => {
249                 PerfTrack.DumpHistogram(_executedInstructions);
250                 Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, (sum, value) => sum + value));
251                 Console.WriteLine("-----");
252
253                 var referenced = new Dictionary<string, int>();
254                 int total = 0;
255                 foreach (var entry in _instances) {
256                     referenced[entry.Key] = entry.Value.Count;
257                     total += entry.Value.Count;
258                 }
259
260                 PerfTrack.DumpHistogram(referenced);
261                 Console.WriteLine("-- Total referenced: {0}", total);
262                 Console.WriteLine("-----");
263             });
264         }
265 #endif
266         public InstructionArray ToArray() {
267 #if STATS
268             lock (_executedInstructions) {
269                 _instructions.ForEach((instr) => {
270                     int value = 0;
271                     var name = instr.GetType().Name;
272                     _executedInstructions.TryGetValue(name, out value);
273                     _executedInstructions[name] = value + 1;
274
275                     Dictionary<object, bool> dict;
276                     if (!_instances.TryGetValue(name, out dict)) {
277                         _instances[name] = dict = new Dictionary<object, bool>();
278                     }
279                     dict[instr] = true;
280                 });
281             }
282 #endif
283             return new InstructionArray(
284                 _maxStackDepth,
285                 _maxContinuationDepth,
286                 _instructions.ToArray(),                
287                 (_objects != null) ? _objects.ToArray() : null,
288                 BuildRuntimeLabels(),
289                 _debugCookies
290             );
291         }
292
293         #endregion
294
295         #region Stack Operations
296
297         private const int PushIntMinCachedValue = -100;
298         private const int PushIntMaxCachedValue = 100;
299         private const int CachedObjectCount = 256;
300
301         private static Instruction _null;
302         private static Instruction _true;
303         private static Instruction _false;
304         private static Instruction[] _ints;
305         private static Instruction[] _loadObjectCached;
306
307         public void EmitLoad(object value) {
308             EmitLoad(value, null);
309         }
310
311         public void EmitLoad(bool value) {
312             if ((bool)value) {
313                 Emit(_true ?? (_true = new LoadObjectInstruction(value)));
314             } else {
315                 Emit(_false ?? (_false = new LoadObjectInstruction(value)));
316             }
317         }
318
319         public void EmitLoad(object value, Type type) {
320             if (value == null) {
321                 Emit(_null ?? (_null = new LoadObjectInstruction(null)));
322                 return;
323             }
324
325             if (type == null || type.IsValueType()) {
326                 if (value is bool) {
327                     EmitLoad((bool)value);
328                     return;
329                 } 
330                 
331                 if (value is int) {
332                     int i = (int)value;
333                     if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) {
334                         if (_ints == null) {
335                             _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1];
336                         }
337                         i -= PushIntMinCachedValue;
338                         Emit(_ints[i] ?? (_ints[i] = new LoadObjectInstruction(value)));
339                         return;
340                     }
341                 }
342             }
343
344             if (_objects == null) {
345                 _objects = new List<object>();
346                 if (_loadObjectCached == null) {
347                     _loadObjectCached = new Instruction[CachedObjectCount];
348                 }
349             }
350
351             if (_objects.Count < _loadObjectCached.Length) {
352                 uint index = (uint)_objects.Count;
353                 _objects.Add(value);
354                 Emit(_loadObjectCached[index] ?? (_loadObjectCached[index] = new LoadCachedObjectInstruction(index)));
355             } else {
356                 Emit(new LoadObjectInstruction(value));
357             }
358         }
359
360         public void EmitDup() {
361             Emit(DupInstruction.Instance);
362         }
363
364         public void EmitPop() {
365             Emit(PopInstruction.Instance);
366         }
367
368         #endregion
369
370         #region Locals
371
372         internal void SwitchToBoxed(int index, int instructionIndex) {
373             var instruction = _instructions[instructionIndex] as IBoxableInstruction;
374
375             if (instruction != null) {
376                 var newInstruction = instruction.BoxIfIndexMatches(index);
377                 if (newInstruction != null) {
378                     _instructions[instructionIndex] = newInstruction;
379                 }
380             }
381         }
382
383         private const int LocalInstrCacheSize = 64;
384
385         private static Instruction[] _loadLocal;
386         private static Instruction[] _loadLocalBoxed;
387         private static Instruction[] _loadLocalFromClosure;
388         private static Instruction[] _loadLocalFromClosureBoxed;
389         private static Instruction[] _assignLocal;
390         private static Instruction[] _storeLocal;
391         private static Instruction[] _assignLocalBoxed;
392         private static Instruction[] _storeLocalBoxed;
393         private static Instruction[] _assignLocalToClosure;
394         private static Instruction[] _initReference;
395         private static Instruction[] _initImmutableRefBox;
396         private static Instruction[] _parameterBox;
397         private static Instruction[] _parameter;
398
399         public void EmitLoadLocal(int index) {
400             if (_loadLocal == null) {
401                 _loadLocal = new Instruction[LocalInstrCacheSize];
402             }
403
404             if (index < _loadLocal.Length) {
405                 Emit(_loadLocal[index] ?? (_loadLocal[index] = new LoadLocalInstruction(index)));
406             } else {
407                 Emit(new LoadLocalInstruction(index));
408             }
409         }
410
411         public void EmitLoadLocalBoxed(int index) {
412             Emit(LoadLocalBoxed(index));
413         }
414
415         internal static Instruction LoadLocalBoxed(int index) {
416             if (_loadLocalBoxed == null) {
417                 _loadLocalBoxed = new Instruction[LocalInstrCacheSize];
418             }
419
420             if (index < _loadLocalBoxed.Length) {
421                 return _loadLocalBoxed[index] ?? (_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index));
422             } else {
423                 return new LoadLocalBoxedInstruction(index);
424             }
425         }
426
427         public void EmitLoadLocalFromClosure(int index) {
428             if (_loadLocalFromClosure == null) {
429                 _loadLocalFromClosure = new Instruction[LocalInstrCacheSize];
430             }
431
432             if (index < _loadLocalFromClosure.Length) {
433                 Emit(_loadLocalFromClosure[index] ?? (_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index)));
434             } else {
435                 Emit(new LoadLocalFromClosureInstruction(index));
436             }
437         }
438
439         public void EmitLoadLocalFromClosureBoxed(int index) {
440             if (_loadLocalFromClosureBoxed == null) {
441                 _loadLocalFromClosureBoxed = new Instruction[LocalInstrCacheSize];
442             }
443
444             if (index < _loadLocalFromClosureBoxed.Length) {
445                 Emit(_loadLocalFromClosureBoxed[index] ?? (_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index)));
446             } else {
447                 Emit(new LoadLocalFromClosureBoxedInstruction(index));
448             }
449         }
450
451         public void EmitAssignLocal(int index) {
452             if (_assignLocal == null) {
453                 _assignLocal = new Instruction[LocalInstrCacheSize];
454             }
455
456             if (index < _assignLocal.Length) {
457                 Emit(_assignLocal[index] ?? (_assignLocal[index] = new AssignLocalInstruction(index)));
458             } else {
459                 Emit(new AssignLocalInstruction(index));
460             }
461         }
462
463         public void EmitStoreLocal(int index) {
464             if (_storeLocal == null) {
465                 _storeLocal = new Instruction[LocalInstrCacheSize];
466             }
467
468             if (index < _storeLocal.Length) {
469                 Emit(_storeLocal[index] ?? (_storeLocal[index] = new StoreLocalInstruction(index)));
470             } else {
471                 Emit(new StoreLocalInstruction(index));
472             }
473         }
474
475         public void EmitAssignLocalBoxed(int index) {
476             Emit(AssignLocalBoxed(index));
477         }
478
479         internal static Instruction AssignLocalBoxed(int index) {
480             if (_assignLocalBoxed == null) {
481                 _assignLocalBoxed = new Instruction[LocalInstrCacheSize];
482             }
483
484             if (index < _assignLocalBoxed.Length) {
485                 return _assignLocalBoxed[index] ?? (_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index));
486             } else {
487                 return new AssignLocalBoxedInstruction(index);
488             }
489         }
490
491         public void EmitStoreLocalBoxed(int index) {
492             Emit(StoreLocalBoxed(index));
493         }
494
495         internal static Instruction StoreLocalBoxed(int index) {
496             if (_storeLocalBoxed == null) {
497                 _storeLocalBoxed = new Instruction[LocalInstrCacheSize];
498             }
499
500             if (index < _storeLocalBoxed.Length) {
501                 return _storeLocalBoxed[index] ?? (_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index));
502             } else {
503                 return new StoreLocalBoxedInstruction(index);
504             }
505         }
506
507         public void EmitAssignLocalToClosure(int index) {
508             if (_assignLocalToClosure == null) {
509                 _assignLocalToClosure = new Instruction[LocalInstrCacheSize];
510             }
511
512             if (index < _assignLocalToClosure.Length) {
513                 Emit(_assignLocalToClosure[index] ?? (_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index)));
514             } else {
515                 Emit(new AssignLocalToClosureInstruction(index));
516             }
517         }
518
519         public void EmitStoreLocalToClosure(int index) {
520             EmitAssignLocalToClosure(index);
521             EmitPop();
522         }
523
524         public void EmitInitializeLocal(int index, Type type) {
525             object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
526             if (value != null) {
527                 Emit(new InitializeLocalInstruction.ImmutableValue(index, value));
528             } else if (type.IsValueType()) {
529                 Emit(new InitializeLocalInstruction.MutableValue(index, type));
530             } else {
531                 Emit(InitReference(index));
532             }
533         }
534
535         internal void EmitInitializeParameter(int index) {
536             Emit(Parameter(index));
537         }
538
539         internal static Instruction Parameter(int index) {
540             if (_parameter == null) {
541                 _parameter = new Instruction[LocalInstrCacheSize];
542             }
543
544             if (index < _parameter.Length) {
545                 return _parameter[index] ?? (_parameter[index] = new InitializeLocalInstruction.Parameter(index));
546             }
547
548             return new InitializeLocalInstruction.Parameter(index);
549         }
550
551         internal static Instruction ParameterBox(int index) {
552             if (_parameterBox == null) {
553                 _parameterBox = new Instruction[LocalInstrCacheSize];
554             }
555
556             if (index < _parameterBox.Length) {
557                 return _parameterBox[index] ?? (_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index));
558             }
559
560             return new InitializeLocalInstruction.ParameterBox(index);
561         }
562
563         internal static Instruction InitReference(int index) {
564             if (_initReference == null) {
565                 _initReference = new Instruction[LocalInstrCacheSize];
566             }
567
568             if (index < _initReference.Length) {
569                 return _initReference[index] ?? (_initReference[index] = new InitializeLocalInstruction.Reference(index));
570             }
571
572             return new InitializeLocalInstruction.Reference(index);
573         }
574
575         internal static Instruction InitImmutableRefBox(int index) {
576             if (_initImmutableRefBox == null) {
577                 _initImmutableRefBox = new Instruction[LocalInstrCacheSize];
578             }
579
580             if (index < _initImmutableRefBox.Length) {
581                 return _initImmutableRefBox[index] ?? (_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null));
582             }
583
584             return new InitializeLocalInstruction.ImmutableBox(index, null);
585         }
586
587         public void EmitNewRuntimeVariables(int count) {
588             Emit(new RuntimeVariablesInstruction(count));
589         }
590
591         #endregion
592
593         #region Array Operations
594
595         public void EmitGetArrayItem(Type arrayType) {
596             Type elementType = arrayType.GetElementType();
597             if (elementType.IsClass() || elementType.IsInterface()) {
598                 Emit(InstructionFactory<object>.Factory.GetArrayItem());
599             } else {
600                 Emit(InstructionFactory.GetFactory(elementType).GetArrayItem());
601             }
602         }
603
604         public void EmitGetArrayLength(Type arrayType) {
605             Emit(GetArrayLengthInstruction.Create());
606         }
607
608         public void EmitSetArrayItem(Type arrayType) {
609             Type elementType = arrayType.GetElementType();
610             if (elementType.IsClass() || elementType.IsInterface()) {
611                 Emit(InstructionFactory<object>.Factory.SetArrayItem());
612             } else {
613                 Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
614             }
615         }
616
617         public void EmitNewArray(Type elementType) {
618             Emit(InstructionFactory.GetFactory(elementType).NewArray());
619         }
620
621         public void EmitNewArrayBounds(Type elementType, int rank) {
622             Emit(new NewArrayBoundsInstruction(elementType, rank));
623         }
624
625         public void EmitNewArrayInit(Type elementType, int elementCount) {
626             Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
627         }
628
629         #endregion
630
631         #region Arithmetic Operations
632
633         public void EmitAdd(Type type, bool @checked) {
634             if (@checked) {
635                 Emit(AddOvfInstruction.Create(type));
636             } else {
637                 Emit(AddInstruction.Create(type));
638             }
639         }
640
641         public void EmitSub(Type type, bool @checked) {
642             if (@checked) {
643                 Emit(SubOvfInstruction.Create(type));
644             } else {
645                 Emit(SubInstruction.Create(type));
646             }
647         }
648
649         public void EmitMul(Type type, bool @checked) {
650             if (@checked) {
651                 Emit(MulOvfInstruction.Create(type));
652             } else {
653                 Emit(MulInstruction.Create(type));
654             }
655         }
656
657         public void EmitDiv(Type type) {
658             Emit(DivInstruction.Create(type));
659         }
660
661         public void EmitMod(Type type) {
662             Emit(ModInstruction.Create(type));
663         }
664
665         #endregion
666
667         public void EmitShl(Type type, bool lifted) {
668             Emit(lifted ? ShlInstruction.CreateLifted(type) : ShlInstruction.Create(type));
669         }
670
671         public void EmitShr(Type type, bool lifted) {
672             Emit(lifted ? ShrInstruction.CreateLifted(type) : ShrInstruction.Create(type));
673         }
674
675         public void EmitOr(Type type, bool lifted) {
676             Emit(lifted ? OrInstruction.CreateLifted(type) : OrInstruction.Create(type));
677         }
678
679         public void EmitAnd(Type type, bool lifted) {
680             Emit(lifted ? AndInstruction.CreateLifted (type) : AndInstruction.Create(type));
681         }
682
683         public void EmitExclusiveOr(Type type, bool lifted) {
684             Emit(lifted ? XorInstruction.CreateLifted(type) : XorInstruction.Create(type));
685         }        
686
687         #region Comparisons
688
689                 public void EmitEqual(Type type, bool liftedResult) {
690             Emit(liftedResult ?
691                 EqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
692                 EqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
693         }
694
695         public void EmitNotEqual(Type type, bool liftedResult) {
696             Emit(liftedResult ?
697                 NotEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
698                 NotEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
699         }
700
701         public void EmitLessThan(Type type, bool liftedResult) {
702             Emit(liftedResult ?
703                 LessThanInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
704                 LessThanInstruction.Create(TypeUtils.GetNonNullableType (type)));
705         }
706
707         public void EmitLessThanOrEqual(Type type, bool liftedResult) {
708             Emit(liftedResult ?
709                 LessThanOrEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
710                 LessThanOrEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
711         }
712
713         public void EmitGreaterThan(Type type, bool liftedResult) {
714             Emit(liftedResult ?
715                 GreaterThanInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
716                 GreaterThanInstruction.Create(TypeUtils.GetNonNullableType (type)));
717         }
718
719         public void EmitGreaterThanOrEqual(Type type, bool liftedResult) {
720             Emit(liftedResult ?
721                 GreaterThanOrEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
722                 GreaterThanOrEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
723         }
724
725         #endregion
726
727         #region Conversions
728
729         public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
730             Emit(new NumericConvertInstruction.Checked(from, to));
731         }
732
733         public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
734             Emit(new NumericConvertInstruction.Unchecked(from, to));
735         }
736
737         #endregion
738
739         #region Unary Operators
740
741         public void EmitNegate(Type type, bool @checked, bool lifted) {
742             if (@checked)
743                 Emit(lifted ? NegateOvfInstruction.CreateLifted(type) : NegateOvfInstruction.Create(type));
744             else
745                 Emit(lifted ? NegateInstruction.CreateLifted(type) : NegateInstruction.Create(type));            
746         }
747
748         public void EmitNot(Type type, bool lifted) {
749             Emit(lifted ? NotInstruction.CreateLifted (type) : NotInstruction.Create(type));
750         }
751
752         #endregion
753
754         #region Nullable operations
755
756         public void EmitWrap (Type elementType)
757         {
758             Emit(InstructionFactory.GetFactory(elementType).WrapToNullable (elementType));
759         }
760
761         #endregion
762
763         #region Types
764
765         public void EmitDefaultValue(Type type) {
766             Emit(InstructionFactory.GetFactory(type).DefaultValue());
767         }
768
769         public void EmitNew(ConstructorInfo constructorInfo) {
770             Emit(new NewInstruction(constructorInfo));
771         }
772
773         internal void EmitCreateDelegate(LightDelegateCreator creator) {
774             Emit(new CreateDelegateInstruction(creator));
775         }
776
777         public void EmitTypeEquals() {
778             Emit(TypeEqualsInstruction.Instance);
779         }
780
781         public void EmitTypeIs(Type type) {
782             Emit(InstructionFactory.GetFactory(type).TypeIs());
783         }
784
785         public void EmitTypeAs(Type type) {
786             Emit(InstructionFactory.GetFactory(type).TypeAs());
787         }
788
789         #endregion
790
791         #region Fields and Methods
792
793         private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();
794
795         public void EmitLoadField(FieldInfo field) {
796             Emit(GetLoadField(field));
797         }
798
799         private Instruction GetLoadField(FieldInfo field) {
800             lock (_loadFields) {
801                 Instruction instruction;
802                 if (!_loadFields.TryGetValue(field, out instruction)) {
803                     if (field.IsStatic) {
804                         instruction = new LoadStaticFieldInstruction(field);
805                     } else {
806                         instruction = new LoadFieldInstruction(field);
807                     }
808                     _loadFields.Add(field, instruction);
809                 }
810                 return instruction;
811             }
812         }
813         
814         public void EmitStoreField(FieldInfo field) {
815             if (field.IsStatic) {
816                 Emit(new StoreStaticFieldInstruction(field));
817             } else {
818                 Emit(new StoreFieldInstruction(field));
819             }
820         }
821
822         #endregion
823
824         #region Dynamic
825
826         public void EmitDynamic(Type type, CallSiteBinder binder) {
827             Emit(CreateDynamicInstruction(type, binder));
828         }
829
830         #region Generated Dynamic InstructionList Factory
831
832         // *** BEGIN GENERATED CODE ***
833         // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py
834
835         public void EmitDynamic<T0, TRet>(CallSiteBinder binder) {
836             Emit(DynamicInstruction<T0, TRet>.Factory(binder));
837         }
838
839         public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) {
840             Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));
841         }
842
843         public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) {
844             Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));
845         }
846
847         public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) {
848             Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));
849         }
850
851         public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) {
852             Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));
853         }
854
855         public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) {
856             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));
857         }
858
859         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) {
860             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));
861         }
862
863         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) {
864             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));
865         }
866
867         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) {
868             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));
869         }
870
871         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) {
872             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));
873         }
874
875         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) {
876             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));
877         }
878
879         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) {
880             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));
881         }
882
883         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) {
884             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));
885         }
886
887         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) {
888             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));
889         }
890
891         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) {
892             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));
893         }
894
895
896         // *** END GENERATED CODE ***
897
898         #endregion
899
900         private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
901             new Dictionary<Type, Func<CallSiteBinder, Instruction>>();
902
903         /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception>
904         internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
905             Func<CallSiteBinder, Instruction> factory;
906             lock (_factories) {
907                 if (!_factories.TryGetValue(delegateType, out factory)) {
908                     if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
909                         // TODO: We should generally support void returning binders but the only
910                         // ones that exist are delete index/member who's perf isn't that critical.
911                         return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
912                     }
913
914                     Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
915                     if (instructionType == null) {
916                         return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
917                     }
918
919                     factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));
920                     _factories[delegateType] = factory;
921                 }
922             }
923             return factory(binder);
924         }
925
926         #endregion
927
928         #region Control Flow
929
930         private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };
931
932         private RuntimeLabel[] BuildRuntimeLabels() {
933             if (_runtimeLabelCount == 0) {
934                 return EmptyRuntimeLabels;
935             }
936
937             var result = new RuntimeLabel[_runtimeLabelCount + 1];
938             foreach (BranchLabel label in _labels) {
939                 if (label.HasRuntimeLabel) {
940                     result[label.LabelIndex] = label.ToRuntimeLabel();
941                 }
942             }
943             // "return and rethrow" label:
944             result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
945             return result;
946         }
947
948         public BranchLabel MakeLabel() {
949             if (_labels == null) {
950                 _labels = new List<BranchLabel>();
951             }
952
953             var label = new BranchLabel();
954             _labels.Add(label);
955             return label;
956         }
957
958         internal void FixupBranch(int branchIndex, int offset) {
959             _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);
960         }
961
962         private int EnsureLabelIndex(BranchLabel label) {
963             if (label.HasRuntimeLabel) {
964                 return label.LabelIndex;
965             }
966
967             label.LabelIndex = _runtimeLabelCount;
968             _runtimeLabelCount++;
969             return label.LabelIndex;
970         }
971
972         public int MarkRuntimeLabel() {
973             BranchLabel handlerLabel = MakeLabel();
974             MarkLabel(handlerLabel);
975             return EnsureLabelIndex(handlerLabel);
976         }
977
978         public void MarkLabel(BranchLabel label) {
979             label.Mark(this);
980         }
981
982         public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
983             Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
984         }
985
986         private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
987             Emit(instruction);
988             label.AddBranch(this, Count - 1);
989         }
990
991         public void EmitBranch(BranchLabel label) {
992             EmitBranch(new BranchInstruction(), label);
993         }
994
995         public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
996             EmitBranch(new BranchInstruction(hasResult, hasValue), label);
997         }
998
999         public void EmitCoalescingBranch(BranchLabel leftNotNull) {
1000             EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
1001         }
1002
1003         public void EmitBranchTrue(BranchLabel elseLabel) {
1004             EmitBranch(new BranchTrueInstruction(), elseLabel);
1005         }
1006
1007         public void EmitBranchFalse(BranchLabel elseLabel) {
1008             EmitBranch(new BranchFalseInstruction(), elseLabel);
1009         }
1010
1011         public void EmitBranchNull(BranchLabel elseLabel) {
1012             EmitBranch(new BranchNullInstruction(), elseLabel);
1013         }
1014
1015         public void EmitThrow() {
1016             Emit(ThrowInstruction.Throw);
1017         }
1018
1019         public void EmitThrowVoid() {
1020             Emit(ThrowInstruction.VoidThrow);
1021         }
1022
1023         public void EmitRethrow() {
1024             Emit(ThrowInstruction.Rethrow);
1025         }
1026
1027         public void EmitRethrowVoid() {
1028             Emit(ThrowInstruction.VoidRethrow);
1029         }
1030
1031         public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
1032             Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
1033         }
1034
1035         public void EmitEnterFinally() {
1036             Emit(EnterFinallyInstruction.Instance);
1037         }
1038
1039         public void EmitLeaveFinally() {
1040             Emit(LeaveFinallyInstruction.Instance);
1041         }
1042
1043         public void EmitLeaveFault(bool hasValue) {
1044             Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
1045         }
1046
1047         public void EmitEnterExceptionHandlerNonVoid() {
1048             Emit(EnterExceptionHandlerInstruction.NonVoid);
1049         }
1050
1051         public void EmitEnterExceptionHandlerVoid() {
1052             Emit(EnterExceptionHandlerInstruction.Void);
1053         }
1054
1055         public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
1056             Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
1057         }
1058
1059         public void EmitSwitch(Dictionary<int, int> cases) {
1060             Emit(new SwitchInstruction(cases));
1061         }
1062
1063         #endregion
1064     }
1065 }